我希望找到列表的唯一排列,x = [“$ 5”,“$ 10”,“$ 10”,“TAX”,“$ 5”,“20%”,“BOGO”,“BOGO” ,“TAX”]以9人为一组
我目前正在做的是
from itertools import permutations
x = ["$5", "$10", "$10", "TAX", "$5", "20%", "BOGO", "BOGO", "TAX"]
combos = []
for i in permutations(x, 9):
if i not in combos:
combos.append(i)
print combos
然而,这需要太长时间才能运行,我想知道是否有人可以给我更多 有效的解决方案。
答案 0 :(得分:6)
if i not in combos:
将花费很长时间,因为列表中的成员资格测试是(最坏情况)O(N) - 它必须扫描每个元素。您可以改为使用set
:
>>> from itertools import permutations
>>> x = ["$5", "$10", "$10", "TAX", "$5", "20%", "BOGO", "BOGO", "TAX", "BOGO"]
>>> %time p = set(permutations(x, 9))
CPU times: user 0.88 s, sys: 0.01 s, total: 0.90 s
Wall time: 0.90 s
>>> len(p)
75600
答案 1 :(得分:1)
关于使用快速设置结构的建议很好,但如果您不首先生成不需要的项目,则会获得最佳结果。让我们对x
:
from collections import OrderedDict
x = OrderedDict([("$5", 2), ("$10", 2), ("TAX", 2), ("20%", 1), ("BOGO", 3)])
然后,以下函数应该为您提供非重复排列:
from copy import copy
def permutations_unique(x, curr_list=[]):
if not x:
yield curr_list
return
last_item = None
if curr_list:
last_item = curr_list[-1]
for item in x:
if item != last_item:
for j in range(1, x[item] + 1):
xchild = copy(x)
xchild[item] -= j
if xchild[item] == 0:
del xchild[item]
for y in permutations_unique(xchild, curr_list + [item] * j):
yield y
这是递归。在每个步骤中,我们选择项目和重复次数。另外,我们避免在递归的下一级别选择相同的项目。
对于您的问题实例,此代码比使用set
的方法慢。但是,请尝试使用x = [1] * 30
作为反例。
答案 2 :(得分:0)
运行需要很长时间的原因是,当您将元素附加到列表时,每次查找都需要更长时间,因为它必须(平均)搜索列表的一半。更好的方法是使用字典:
combos = {}
和
if i not in combos:
combos[i] = None # Just to put something there unless you need to store a value
这会利用hash maps的查找性能。
如果您只是进行会员资格测试,请使用DSM建议的套装。