我对如何做到这一点感到有点困惑,我知道它可能也需要一些概率知识(我缺乏)。
我如何计算有多少种方式,并且还可以获得我可以订购列表的方式的所有可能性?
例如,如果我有lst = ["a", "a", "a", "a", "b", "b", "b"]
,我可以订购多少种方式/如何获得所有可能的组合?我一直在浏览itertools
,但还没找到适合自己的东西。
答案 0 :(得分:6)
您可以使用permutations()
获取所有排名,并使用set()
删除重复的项目:
>>> from itertools import permutations
>>> set(permutations(lst))
{('b', 'a', 'b', 'a', 'a', 'a', 'b'), ('b', 'a', 'a', 'b', 'a', 'a', 'b'), ('b', 'a', 'a', 'b', 'b', 'a', 'a'), ('a', 'a', 'b', 'b', 'a', 'a', 'b'), ('a', 'a', 'b', 'a', 'b', 'b', 'a'), ('b', 'b', 'a', 'b', 'a', 'a', 'a'), ('b', 'a', 'a', 'a', 'b', 'a', 'b'), ('b', 'a', 'b', 'a', 'b', 'a', 'a'), ('b', 'b', 'a', 'a', 'b', 'a', 'a'), ('b', 'b', 'b', 'a', 'a', 'a', 'a'), ('a', 'a', 'a', 'b', 'a', 'b', 'b'), ('a', 'a', 'b', 'b', 'b', 'a', 'a'), ('a', 'a', 'a', 'b', 'b', 'b', 'a'), ('a', 'b', 'b', 'a', 'a', 'b', 'a'), ('b', 'a', 'b', 'b', 'a', 'a', 'a'), ('a', 'b', 'b', 'b', 'a', 'a', 'a'), ('a', 'b', 'a', 'a', 'a', 'b', 'b'), ('a', 'b', 'a', 'b', 'a', 'b', 'a'), ('a', 'b', 'b', 'a', 'a', 'a', 'b'), ('a', 'b', 'b', 'a', 'b', 'a', 'a'), ('a', 'a', 'b', 'a', 'b', 'a', 'b'), ('a', 'b', 'a', 'b', 'b', 'a', 'a'), ('b', 'b', 'a', 'a', 'a', 'b', 'a'), ('a', 'a', 'b', 'a', 'a', 'b', 'b'), ('a', 'a', 'a', 'a', 'b', 'b', 'b'), ('b', 'a', 'b', 'a', 'a', 'b', 'a'), ('b', 'b', 'a', 'a', 'a', 'a', 'b'), ('a', 'b', 'a', 'a', 'b', 'b', 'a'), ('b', 'a', 'a', 'b', 'a', 'b', 'a'), ('a', 'a', 'a', 'b', 'b', 'a', 'b'), ('a', 'b', 'a', 'a', 'b', 'a', 'b'), ('a', 'a', 'b', 'b', 'a', 'b', 'a'), ('a', 'b', 'a', 'b', 'a', 'a', 'b'), ('b', 'a', 'a', 'a', 'a', 'b', 'b'), ('b', 'a', 'a', 'a', 'b', 'b', 'a')}
>>>
请注意,他的方法不是一种优化的方法,因为它首先计算所有排列,虽然它返回一个迭代器并且不会将所有这些排列存储在内存中,但它仍然不是最好的方式&#it&#如果你正在处理非大数据集,那就很好。
如果您想使用优化方式,可以自定义permutations
的{{3}}等效函数。
答案 1 :(得分:5)
正如Kasramvd所提到的,使用itertools.permutations
而不是是生成包含重复元素的列表的排列的有效方法。您的示例数据有7个元素,因此itertools.permutations
生成7个! = 5040个排列,但只有35 = 7 choose 3个唯一排列。
幸运的是,由于14世纪的印度数学家Narayana Pandita,它产生了一种古老的排列算法,它以字典顺序产生排列,可以优雅地处理重复元素。这是一个描述(源自Wikipedia文章),显示了该算法如何从当前算法生成下一个排列。
这是一个实现该算法的生成器函数。为了获得所有排列,输入列表必须按字典顺序按升序排序。
def lexico_permute(a):
a = list(a)
yield a
n = len(a) - 1
while True:
for j in range(n-1, -1, -1):
if a[j] < a[j + 1]:
break
else:
return
v = a[j]
for k in range(n, j, -1):
if v < a[k]:
break
a[j], a[k] = a[k], a[j]
a[j+1:] = a[j+1:][::-1]
yield a
# Test
lst = ["a", "a", "a", "a", "b", "b", "b"]
for i, u in enumerate(lexico_permute(lst), 1):
print(i, u)
<强>输出强>
1 ['a', 'a', 'a', 'a', 'b', 'b', 'b']
2 ['a', 'a', 'a', 'b', 'a', 'b', 'b']
3 ['a', 'a', 'a', 'b', 'b', 'a', 'b']
4 ['a', 'a', 'a', 'b', 'b', 'b', 'a']
5 ['a', 'a', 'b', 'a', 'a', 'b', 'b']
6 ['a', 'a', 'b', 'a', 'b', 'a', 'b']
7 ['a', 'a', 'b', 'a', 'b', 'b', 'a']
8 ['a', 'a', 'b', 'b', 'a', 'a', 'b']
9 ['a', 'a', 'b', 'b', 'a', 'b', 'a']
10 ['a', 'a', 'b', 'b', 'b', 'a', 'a']
11 ['a', 'b', 'a', 'a', 'a', 'b', 'b']
12 ['a', 'b', 'a', 'a', 'b', 'a', 'b']
13 ['a', 'b', 'a', 'a', 'b', 'b', 'a']
14 ['a', 'b', 'a', 'b', 'a', 'a', 'b']
15 ['a', 'b', 'a', 'b', 'a', 'b', 'a']
16 ['a', 'b', 'a', 'b', 'b', 'a', 'a']
17 ['a', 'b', 'b', 'a', 'a', 'a', 'b']
18 ['a', 'b', 'b', 'a', 'a', 'b', 'a']
19 ['a', 'b', 'b', 'a', 'b', 'a', 'a']
20 ['a', 'b', 'b', 'b', 'a', 'a', 'a']
21 ['b', 'a', 'a', 'a', 'a', 'b', 'b']
22 ['b', 'a', 'a', 'a', 'b', 'a', 'b']
23 ['b', 'a', 'a', 'a', 'b', 'b', 'a']
24 ['b', 'a', 'a', 'b', 'a', 'a', 'b']
25 ['b', 'a', 'a', 'b', 'a', 'b', 'a']
26 ['b', 'a', 'a', 'b', 'b', 'a', 'a']
27 ['b', 'a', 'b', 'a', 'a', 'a', 'b']
28 ['b', 'a', 'b', 'a', 'a', 'b', 'a']
29 ['b', 'a', 'b', 'a', 'b', 'a', 'a']
30 ['b', 'a', 'b', 'b', 'a', 'a', 'a']
31 ['b', 'b', 'a', 'a', 'a', 'a', 'b']
32 ['b', 'b', 'a', 'a', 'a', 'b', 'a']
33 ['b', 'b', 'a', 'a', 'b', 'a', 'a']
34 ['b', 'b', 'a', 'b', 'a', 'a', 'a']
35 ['b', 'b', 'b', 'a', 'a', 'a', 'a']
FWIW,此代码比问题中给出的列表使用set(permutations(lst))
快约8倍;对于较大的输入列表,节省的时间可以更长。
<小时/>
lexico_permute
最初从输入序列(也可以是元组,字符串等)创建一个新列表。然后它产生新的列表,将其原地推进到下一个排列,并再次产生相同的列表。等等。因此,如果您只是将其输出附加到空列表,您最终会得到一个列表列表,其中只包含对同一列表的多个引用。这通常不是很有用。 :)
解决这个问题的简单方法是附加lexico_permute
所产生的列表副本,例如
all_perms = []
for u in lexico_permute(lst):
all_perms.append(u[:])
或作为列表理解:
all_perms = [u[:] for u in lexico_permute(lst)]
或者,将lexico_permute
中的两个yield语句更改为
yield a[:]
然后你可以做
all_perms = list(lexico_permute(lst))
答案 2 :(得分:0)
听起来你只是想计算可区分排列的数量,而不是生成它们。
如果你有一种 1 无法区分的元素,那么n 2 不可区分的另一种元素,最多n k 元素最后一种,那么你的集合中无法区分的排列数的公式是:
要在Python中计算,我们可以这样做:
from collections import Counter
from math import factorial
from functools import reduce
import operator
def unique_permutations(lst):
c = Counter(lst)
return factorial(len(lst)) // reduce(operator.mul, map(factorial, c.values()))
这是输出:
>>> unique_permutations(["a", "a", "a", "a", "b", "b", "b"])
35