在 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() as “from scipy.special import perm” 如上例,或執行 scipy.special.perm() as “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
重複組合的總數也可以通過第四個參數repetition獲得。這在下面描述。

再次注意,只有“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 模塊的 combine() 函數。

傳遞一個可迭代的(列表或集合類型)作為第一個參數並將要選擇的片段數作為第二個參數返回該組合的迭代器。

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()”中沒有實現參數“repetition”。

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

從列表中生成和枚舉重複組合:itertools.combinations_with_replacement()

可以從列表(數組)等中生成和枚舉所有重複組合以及總數。

使用 itertools 模塊中的 combination_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() 可以輕鬆創建字符串排列(字謎)。

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