具有独特价值的排列
itertools.permutations生成的地方,其元素被视为唯一的基础上他们的立场,而不是他们的价值。 所以基本上我想避免这样的重复:
>>> list(itertools.permutations([1, 1, 1])) [(1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1)]
之后过滤是不可能的,因为在我的情况下,排列的数量太大了。
有人知道一个合适的algorithm吗?
非常感谢你!
编辑:
我基本想要的是以下几点:
x = itertools.product((0, 1, 'x'), repeat=X) x = sorted(x, key=functools.partial(count_elements, elem='x'))
这是不可能的,因为sorted
创build一个列表和itertools.product的输出是太大了。
对不起,我应该描述实际的问题。
class unique_element: def __init__(self,value,occurrences): self.value = value self.occurrences = occurrences def perm_unique(elements): eset=set(elements) listunique = [unique_element(i,elements.count(i)) for i in eset] u=len(elements) return perm_unique_helper(listunique,[0]*u,u-1) def perm_unique_helper(listunique,result_list,d): if d < 0: yield tuple(result_list) else: for i in listunique: if i.occurrences > 0: result_list[d]=i.value i.occurrences-=1 for g in perm_unique_helper(listunique,result_list,d-1): yield g i.occurrences+=1 a = list(perm_unique([1,1,2])) print(a)
结果:
[(2, 1, 1), (1, 2, 1), (1, 1, 2)]
编辑(这是如何工作):
我重写上层程序的时间更长,但更具可读性我通常很难解释事情是如何工作的,但让我试试。 为了理解这是如何工作的,你必须了解类似的,但更简单的程序,将产生重复的所有排列。
def permutations_with_replecement(elements,n): return permutations_helper(elements,[0]*n,n-1)#this is generator def permutations_helper(elements,result_list,d): if d<0: yield tuple(result_list) else: for i in elements: result_list[d]=i all_permutations = permutations_helper(elements,result_list,d-1)#this is generator for g in all_permutations: yield g
这个程序显然要简单得多。 d代表permutations_helper的深度,有两个function。 一个函数是我们的recursionalgorithm的停止条件,另一个是结果列表,这是传递的。
而不是返回每个结果我们得到它。 如果没有函数/操作符的yield
我们不得不在结束条件的时候推结果队列。 但是这样一旦停止条件满足结果传播槽就全部堆栈起来。 这是妓院的
for g in perm_unique_helper(listunique,result_list,d-1): yield g
所以每个结果都传播给调用者。
回到原来的程序:我们有独特的元素列表。 在我们可以使用每个元素之前,我们必须检查它们还有多less可用于将其推到result_list上。 这个程序的工作和permutations_with_replecement
相比是非常相似的,每个元素不能重复多次,就是在perm_unique_helper中。
这依赖于实现细节,sorting后的迭代的任何排列都是按sorting顺序排列的,除非它们是先前排列的重复。
from itertools import permutations def unique_permutations(iterable, r=None): previous = tuple() for p in permutations(sorted(iterable), r): if p > previous: previous = p yield p for p in unique_permutations('cabcab', 2): print p
给
('a', 'a') ('a', 'b') ('a', 'c') ('b', 'a') ('b', 'b') ('b', 'c') ('c', 'a') ('c', 'b') ('c', 'c')
你可以尝试使用set:
>>> list(itertools.permutations(set([1,1,2,2]))) [(1, 2), (2, 1)]
呼叫设置删除重复
大致和Luka Rahne的回答一样快,但更简单,恕我直言。
def unique_permutations(elements): if len(elements) == 1: yield (elements[0],) else: unique_elements = set(elements) for first_element in unique_elements: remaining_elements = list(elements) remaining_elements.remove(first_element) for sub_permutation in unique_permutations(remaining_elements): yield (first_element,) + sub_permutation >>> list(unique_permutations((1,2,3,1))) [(1, 1, 2, 3), (1, 1, 3, 2), (1, 2, 1, 3), ... , (3, 1, 2, 1), (3, 2, 1, 1)]
它通过设置第一个元素(遍历所有唯一元素)recursion地工作,并遍历所有剩余元素的排列。
让我们通过(1,2,3,1)的unique_permutations
来看看它是如何工作的:
-
unique_elements
是1,2,3 - 让我们遍历它们:
first_element
从1开始。-
remaining_elements
是[2,3,1](即1,2,3,1减去前1) - (1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1, 2),(3,2,1)
- 对于每个
sub_permutation
,我们插入first_element
:(first_element
),(first_element
),…并产生结果。
-
- 现在我们迭代到
first_element
= 2,并且像上面那样做。-
remaining_elements
是[1,3,1](即1,2,3,1减去前两个) - 我们遍历其余元素的排列:(1,1,3),(1,3,1),(3,1,1)
- 对于每个
sub_permutation
,我们插入first_element
:(first_element
),(first_element
),(first_element
)…并产生结果。
-
- 最后,我们用
first_element
= 3来做同样的first_element
。
这是我用10行的解决scheme:
class Solution(object): def permute_unique(self, nums): perms = [[]] for n in nums: new_perm = [] for perm in perms: for i in range(len(perm) + 1): new_perm.append(perm[:i] + [n] + perm[i:]) # handle duplication if i < len(perm) and perm[i] == n: break perms = new_perm return perms if __name__ == '__main__': s = Solution() print s.permute_unique([1, 1, 1]) print s.permute_unique([1, 2, 1]) print s.permute_unique([1, 2, 3])
—结果—-
[[1, 1, 1]] [[1, 2, 1], [2, 1, 1], [1, 1, 2]] [[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]]
因为有时候新的问题被标记为重复的,并且他们的作者被提及到这个问题,可能很重要的一点是sympy有一个用于这个目的的迭代器。
>>> from sympy.utilities.iterables import multiset_permutations >>> list(multiset_permutations([1,1,1])) [[1, 1, 1]] >>> list(multiset_permutations([1,1,2])) [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
这听起来像你正在寻找itertools.combinations() docs.python.org
list(itertools.combinations([1, 1, 1],3)) [(1, 1, 1)]
碰到这个问题,一边寻找自己的东西!
以下是我所做的:
def dont_repeat(x=[0,1,1,2]): # Pass a list from itertools import permutations as per uniq_set = set() for byt_grp in per(x, 4): if byt_grp not in uniq_set: yield byt_grp uniq_set.update([byt_grp]) print uniq_set for i in dont_repeat(): print i (0, 1, 1, 2) (0, 1, 2, 1) (0, 2, 1, 1) (1, 0, 1, 2) (1, 0, 2, 1) (1, 1, 0, 2) (1, 1, 2, 0) (1, 2, 0, 1) (1, 2, 1, 0) (2, 0, 1, 1) (2, 1, 0, 1) (2, 1, 1, 0) set([(0, 1, 1, 2), (1, 0, 1, 2), (2, 1, 0, 1), (1, 2, 0, 1), (0, 1, 2, 1), (0, 2, 1, 1), (1, 1, 2, 0), (1, 2, 1, 0), (2, 1, 1, 0), (1, 0, 2, 1), (2, 0, 1, 1), (1, 1, 0, 2)])
基本上,做一个集合,不断增加它。 比列表等内容更好,希望它有助于下一个人看:-)注释掉function设置“更新”,看看有什么不同。
关于什么
np.unique(itertools.permutations([1, 1, 1]))
问题是排列现在是一个Numpy数组的行,因此使用更多的内存,但你可以像以前一样循环
perms = np.unique(itertools.permutations([1, 1, 1])) for p in perms: print p
有一天,我在处理自己的问题的时候遇到了这个问题。 我喜欢Luka Rahne的方法,但是我认为在集合库中使用Counter类似乎是一个适度的改进。 这是我的代码:
def unique_permutations(elements): "Returns a list of lists; each sublist is a unique permutations of elements." ctr = collections.Counter(elements) # Base case with one element: just return the element if len(ctr.keys())==1 and ctr[ctr.keys()[0]] == 1: return [[ctr.keys()[0]]] perms = [] # For each counter key, find the unique permutations of the set with # one member of that key removed, and append the key to the front of # each of those permutations. for k in ctr.keys(): ctr_k = ctr.copy() ctr_k[k] -= 1 if ctr_k[k]==0: ctr_k.pop(k) perms_k = [[k] + p for p in unique_permutations(ctr_k)] perms.extend(perms_k) return perms
此代码将每个排列返回为一个列表。 如果你给它一个string,它会给你一个排列列表,其中每个列表是一个字符列表。 如果您希望将输出结果作为string列表(例如,如果您是一个可怕的人,并且想要滥用我的代码来帮助您在拼字游戏中作弊),请执行以下操作:
[''.join(perm) for perm in unique_permutations('abunchofletters')]