在Python中计算和生成阶乘、排列和组合

商业

Python中数学函数的标准模块math可以用来计算阶乘。SciPy也有函数来计算排列组合的总数。

itertools模块也可以用来从列表(数组)等中生成排列组合,并对其进行枚举。

这里解释一下,并附有示例代码。

  • 系数:math.factorial()
  • 计算排列组合的总数
    • math.factorial()
    • scipy.special.perm()
  • 从一个列表中生成和列举排列组合:itertools.permutations()
  • 计算组合的总数量
    • math.factorial()
    • scipy.special.comb()
    • 如何不使用math.factorial()?
  • 从列表中生成和列举组合:itertools.combinations()
  • 计算出重复组合的总数量
  • 从列表中生成并列举出重复的组合:itertools.combinations_with_replacement()

作为利用排列组合的一个例子,下面还将解释。

  • 从字符串中创造一个个字母

如果你想生成多个列表的元素组合,而不是单一的列表,请使用itertools模块中的itertools.product()。

系数: math.factorial()

数学模块提供了一个函数 factorial(),用于返回阶乘。

import math

print(math.factorial(5))
# 120

print(math.factorial(0))
# 1

非整数、负值将导致一个ValueError。

# print(math.factorial(1.5))
# ValueError: factorial() only accepts integral values

# print(math.factorial(-1))
# ValueError: factorial() not defined for negative values

计算排列组合的总数

math.factorial()

排列是指从n个不同的中选取r并放在一行中的情况的数量。

使用阶乘的方式,通过以下公式得到排列组合的总数p。

p = n! / (n - r)!

可以用函数math.factorial()进行如下计算,它返回阶乘。⌘运算符,执行整数除法,用于返回一个整数类型。

def permutations_count(n, r):
    return math.factorial(n) // math.factorial(n - r)

print(permutations_count(4, 2))
# 12

print(permutations_count(4, 4))
# 24

scipy.special.perm()

SciPy提供了一个函数scipy.special.perm()来返回排列组合的总数。需要单独安装SciPy。从0.14.0版本开始提供。

from scipy.special import perm

print(perm(4, 2))
# 12.0

print(perm(4, 2, exact=True))
# 12

print(perm(4, 4, exact=True))
# 24

exact=False
第三个参数默认设置如上,返回一个浮点数。请注意,如果你想得到的是一个整数,你需要按以下方式设置它。
exact=True

注意,只有 “import scipy “不会加载scipy.special模块。

像上面的例子一样,将perm()执行为 “from scipy.special import perm”,或者将scipy.special.perm()执行为 “import scipy.special”。

从一个列表中生成和列举排列组合: itertools.permutations()

不仅是总数,还可以从列表(数组)中生成和列举排列组合,等等。

使用itertools模块的permutations()函数。

传递一个迭代器(列表或集合类型)作为第一个参数,传递要选择的件数作为第二个参数,就会返回一个该排列组合的迭代器。

import itertools

l = ['a', 'b', 'c', 'd']

p = itertools.permutations(l, 2)

print(type(p))
# <class 'itertools.permutations'>

要列举所有这些,你可以使用for循环。

for v in itertools.permutations(l, 2):
    print(v)
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'a')
# ('b', 'c')
# ('b', 'd')
# ('c', 'a')
# ('c', 'b')
# ('c', 'd')
# ('d', 'a')
# ('d', 'b')
# ('d', 'c')

由于它是一个有限的迭代器,它也可以用list()转换为一个列表类型。

当用len()得到列表中的元素数时,可以确认它与由阶乘计算出的排列组合总数相匹配。

p_list = list(itertools.permutations(l, 2))

print(p_list)
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'a'), ('b', 'c'), ('b', 'd'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('d', 'a'), ('d', 'b'), ('d', 'c')]

print(len(p_list))
# 12

如果省略第二个参数,将返回选择所有元素的排列组合。

for v in itertools.permutations(l):
    print(v)
# ('a', 'b', 'c', 'd')
# ('a', 'b', 'd', 'c')
# ('a', 'c', 'b', 'd')
# ('a', 'c', 'd', 'b')
# ('a', 'd', 'b', 'c')
# ('a', 'd', 'c', 'b')
# ('b', 'a', 'c', 'd')
# ('b', 'a', 'd', 'c')
# ('b', 'c', 'a', 'd')
# ('b', 'c', 'd', 'a')
# ('b', 'd', 'a', 'c')
# ('b', 'd', 'c', 'a')
# ('c', 'a', 'b', 'd')
# ('c', 'a', 'd', 'b')
# ('c', 'b', 'a', 'd')
# ('c', 'b', 'd', 'a')
# ('c', 'd', 'a', 'b')
# ('c', 'd', 'b', 'a')
# ('d', 'a', 'b', 'c')
# ('d', 'a', 'c', 'b')
# ('d', 'b', 'a', 'c')
# ('d', 'b', 'c', 'a')
# ('d', 'c', 'a', 'b')
# ('d', 'c', 'b', 'a')

print(len(list(itertools.permutations(l))))
# 24

在itertools.permutations()中,元素的处理是基于位置,而不是价值。重复的值不会被考虑在内。

l = ['a', 'a']

for v in itertools.permutations(l, 2):
    print(v)
# ('a', 'a')
# ('a', 'a')

这同样适用于以下功能,如下所述。

  • itertools.combinations()
  • itertools.combinations_with_replacement()

计算组合的总数量

math.factorial()

组合的数量是指从n个不同的棋子中选择r个棋子的数量。顺序并不像排列组合那样被考虑。

组合的总数c由以下公式得到。

c = n! / (r! * (n - r)!)

可以用函数math.factorial()进行如下计算,它返回阶乘。⌘运算符,执行整数除法,用于返回一个整数类型。

def combinations_count(n, r):
    return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))

print(combinations_count(4, 2))
# 6

scipy.special.comb()

SciPy提供了一个函数scipy.special.comb()来返回排列组合的总数。需要单独安装SciPy。从0.14.0版本开始提供。注意,scipy.misc.comb()没有实现下面描述的参数重复。

from scipy.special import comb

print(comb(4, 2))
# 6.0

print(comb(4, 2, exact=True))
# 6

print(comb(4, 0, exact=True))
# 1

exact=False
和scipy.special.perm()一样,第三个参数默认设置为上述参数,返回一个浮点数。注意,如果你想得到它是一个整数,你需要按如下方法设置它。
exact=True
重复组合的总数也可以通过第四个参数,即重复来获得。这将在下面描述。

再次注意,只有 “import scipy “不会加载scipy.special模块。

如上面的例子,执行 comb() 为 “from scipy.special import comb” 或执行 scipy.special.comb() 为 “import scipy.special” 。这同样适用于 “scipy.misc”。

如何不使用math.factorial()?

另一个只使用标准库的方法,比使用math.factorial()的方法更快,是以下方法。

from operator import mul
from functools import reduce

def combinations_count(n, r):
    r = min(r, n - r)
    numer = reduce(mul, range(n, n - r, -1), 1)
    denom = reduce(mul, range(1, r + 1), 1)
    return numer // denom

print(combinations_count(4, 2))
# 6

print(combinations_count(4, 0))
# 1

从列表中生成和列举组合: itertools.combinations()

可以从列表(数组)等中生成和列举所有的组合,也可以生成和列举总数字。

使用itertools模块的combinations()函数。

传递一个迭代器(列表或集合类型)作为第一个参数,传递要选择的件数作为第二个参数,返回该组合的迭代器。

l = ['a', 'b', 'c', 'd']

c = itertools.combinations(l, 2)

print(type(c))
# <class 'itertools.combinations'>

for v in itertools.combinations(l, 2):
    print(v)
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'c')
# ('b', 'd')
# ('c', 'd')

c_list = list(itertools.combinations(l, 2))

print(c_list)
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

print(len(c_list))
# 6

计算出重复组合的总数量

重复组合的数量是指在允许重复的情况下,从n个不同的组合中选择r的数量。

重复组合的总数等于从(n + r – 1)个不同的组合中选择(r)个组合。

因此,我们可以使用上面定义的函数来计算组合的总数。

def combinations_with_replacement_count(n, r):
    return combinations_count(n + r - 1, r)

print(combinations_with_replacement_count(4, 2))
# 10

在上面描述的 “scipy.special.comb() “中,通过设置第四个参数 “repetition=True “可以获得重复组合的总数。
注意,在 “SciPy0.14.0 “之前的版本中,”scipy.misc.comb() “没有实现参数 “重复”。

from scipy.special import comb
print(comb(4, 2, exact=True, repetition=True))
# 10

从列表中生成并列举出重复的组合: itertools.combinations_with_replacement()

可以从列表(数组)等中生成和列举所有重复的组合,也可以生成和列举总数。

使用itertools模块中的combinations_with_replacement()函数。

传递一个迭代器(列表或集合类型)作为第一个参数,传递要选择的件数作为第二个参数,返回该重叠组合的一个迭代器。

h = itertools.combinations_with_replacement(l, 2)

print(type(h))
# <class 'itertools.combinations_with_replacement'>

for v in itertools.combinations_with_replacement(l, 2):
    print(v)
# ('a', 'a')
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'b')
# ('b', 'c')
# ('b', 'd')
# ('c', 'c')
# ('c', 'd')
# ('d', 'd')

h_list = list(itertools.combinations_with_replacement(l, 2))

print(h_list)
# [('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('c', 'c'), ('c', 'd'), ('d', 'd')]

print(len(h_list))
# 10

从字符串中创造一个个字母

Itertools.permutations()可以很容易地创建字符串的排列组合(agrams)。

s = 'arc'

for v in itertools.permutations(s):
    print(v)
# ('a', 'r', 'c')
# ('a', 'c', 'r')
# ('r', 'a', 'c')
# ('r', 'c', 'a')
# ('c', 'a', 'r')
# ('c', 'r', 'a')

要将一次一个字符的元组合并成一个字符串,并使其成为一个列表,请执行以下操作

anagram_list = [''.join(v) for v in itertools.permutations(s)]

print(anagram_list)
# ['arc', 'acr', 'rac', 'rca', 'car', 'cra']

join()方法将一个列表或元组的元素连接成一个字符串,并使用了列表理解符号。

Copied title and URL