具有独特价值的排列

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')]