简体   繁体   English

首先在Python中枚举数量最少的3排列

[英]Enumerate 3-permutations with lowest numbers first in Python

This works in Python to display all the 3-permutations of [0, 1, 2, 3, 4] : 这可以在Python中显示[0, 1, 2, 3, 4]所有3个排列

import itertools
N = 5
for p in itertools.permutations(range(N), r=3):
    print p

#(0, 1, 2)
#(0, 1, 3)
#(0, 1, 4)
#(0, 2, 1)
#(0, 2, 3)
#(0, 2, 4)
#(0, 3, 1)
#...

But I'd like to have them enumerated in this order: lowest number firsts, ie: 但我想按以下顺序枚举它们:最低的数字优先,即:

#display 3-permutations of [0]
# (none)

#display 3-permutations of [0, 1] that haven't been displayed before
# (none)

#display 3-permutations of [0, 1, 2] that haven't been displayed before
(0, 1, 2)
(0, 2, 1)
(1, 0, 2)
(1, 2, 0)
(2, 0, 1)
(2, 1, 0)

#display 3-permutations of [0, 1, 2, 3] that haven't been displayed before
(0, 1, 3)
(0, 2, 3)
(0, 3, 1)
(0, 3, 2)
...

#display remaining 3-permutations of [0, 1, 2, 3, 4] that haven't been displayed before
...

Is there a way to quickly enumerate 3-permutations of [0, ..., N-1] with this order? 有没有一种方法可以以此顺序快速枚举[0,...,N-1]的3个排列?


Note: In my use case, N > 2000 , so it has to be fast (I'm using Cython as well for other computations to make it fast, but this is another topic). 注意:在我的用例中, N > 2000 ,所以它必须快(我也使用Cython进行其他计算以使其快,但这是另一个主题)。

Edit (thanks to @RoryDaulton): the order within each group does not matter and I only care about the grouping. 编辑(由于@RoryDaulton):每个组中的顺序无关紧要,我只关心分组。

Here is an algorithm that is pretty fast and uses almost no extra memory. 这是一种非常快速的算法,几乎不占用额外的内存。

First, use itertools to enumerate the 3-permuations of [0, 1, 2] . 首先,使用itertools枚举[0, 1, 2]的3个置换。

Then, enumerate the 2-permutations of [0, 1, 2] , and just before yielding each permutation insert a 3 at the end. 然后,枚举[0, 1, 2]的2个置换,并在产生每个置换之前将3插入末尾。 Then enumerate those 2-permutations again and insert a 3 at the middle position. 然后再次枚举这些2排列,并在中间位置插入3 Then enumerate them again and insert a 3 at the beginning position. 然后再次枚举它们,并在开始位置插入3

Then enumerate the 2-permutations of [0, 1, 2, 3] and insert a 4 at the end. 然后枚举[0, 1, 2, 3]的2个置换,并在末尾插入4 Then enumerate those 2-permutations again and insert a 4 at the middle position. 然后再次枚举那些2排列,并在中间位置插入4 Then... 然后...

You get the idea. 你明白了。 You might save some time by saving the 2-permutations after the first generation so you can just insert the large value at the proper place. 通过在第一代之后保存2个置换,您可以节省一些时间,因此您只需在适当的位置插入较大的值即可。

NOTE: I proposed this algorithm to get the exact order of 3-permutations given in the example. 注意:我提出此算法以获取示例中给出的3排列的确切顺序。 If the order within a group can differ, other algorithms are possible and are faster than mine. 如果组中的顺序可以不同,则其他算法也是可能的,并且比我的算法更快。 My algorithm works just fine and gives the stated order completely, but it is slower than the algorithms with a different order. 我的算法可以很好地工作并完全给出指定的顺序,但是它比具有不同顺序的算法要慢。

The search for p in the set can probably be optimized, but one way to achieve the goal of displaying the permutations themselves it is by using sets: 在集合中搜索p可能可以优化,但是一种实现显示自身排列的目标的方法是使用集合:

import itertools
N = 5
spam = set()
for i in range(N):
    print('new permutation', list(range(i+1)))
    for p in itertools.permutations(range(i+1), r=3):
        if p not in spam:
            print(p)
            spam.add(p)

I've finally found a solution, which seems to be optimal: 我终于找到了一个最佳的解决方案:

for i in range(N):            # i is the biggest
    print 'biggest = %i' % i
    for j in range(i):        # j is the second
        for k in range(j):    # k is the smallest
                print i, j, k
                print j, k, i
                print k, i, j
                print j, i, k
                print k, j, i
                print i, k, j

Here is the output 这是输出

biggest = 0
biggest = 1
biggest = 2
2 1 0
1 0 2
0 2 1
1 2 0
0 1 2
2 0 1
biggest = 3
3 1 0
1 0 3
0 3 1
1 3 0
0 1 3
3 0 1
3 2 0
2 0 3
0 3 2
2 3 0
0 2 3
3 0 2
3 2 1
2 1 3
1 3 2
2 3 1
1 2 3
3 1 2
biggest = 4
4 1 0
1 0 4
0 4 1
1 4 0
0 1 4
4 0 1
4 2 0
2 0 4
0 4 2
2 4 0
0 2 4
4 0 2
4 2 1
2 1 4
1 4 2
2 4 1
1 2 4
4 1 2
4 3 0
3 0 4
0 4 3
3 4 0
0 3 4
4 0 3
4 3 1
3 1 4
1 4 3
3 4 1
1 3 4
4 1 3
4 3 2
3 2 4
2 4 3
3 4 2
2 3 4
4 2 3

Your answer looks like the best approach, but you can make it a little more compact (and improve the ordering) by using permutations . 您的答案似乎是最好的方法,但是您可以通过使用permutations使它更紧凑(并改善排序)。

from itertools import permutations

num = 5
for i in range(2, num):
    for j in range(i):
        for k in range(j):
            for t in permutations((k, j, i)):
                print(t)

output 输出

(0, 1, 2)
(0, 2, 1)
(1, 0, 2)
(1, 2, 0)
(2, 0, 1)
(2, 1, 0)
(0, 1, 3)
(0, 3, 1)
(1, 0, 3)
(1, 3, 0)
(3, 0, 1)
(3, 1, 0)
(0, 2, 3)
(0, 3, 2)
(2, 0, 3)
(2, 3, 0)
(3, 0, 2)
(3, 2, 0)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
(0, 1, 4)
(0, 4, 1)
(1, 0, 4)
(1, 4, 0)
(4, 0, 1)
(4, 1, 0)
(0, 2, 4)
(0, 4, 2)
(2, 0, 4)
(2, 4, 0)
(4, 0, 2)
(4, 2, 0)
(1, 2, 4)
(1, 4, 2)
(2, 1, 4)
(2, 4, 1)
(4, 1, 2)
(4, 2, 1)
(0, 3, 4)
(0, 4, 3)
(3, 0, 4)
(3, 4, 0)
(4, 0, 3)
(4, 3, 0)
(1, 3, 4)
(1, 4, 3)
(3, 1, 4)
(3, 4, 1)
(4, 1, 3)
(4, 3, 1)
(2, 3, 4)
(2, 4, 3)
(3, 2, 4)
(3, 4, 2)
(4, 2, 3)
(4, 3, 2)

Here's some code I came up with earlier. 这是我之前提出的一些代码。 It's more compact, but it uses a lot of RAM when N is large. 它更紧凑,但是当N很大时会占用大量RAM。

from itertools import permutations

num = 5
a = [(i, 1<<i) for i in range(num)]
perms = sorted(permutations(a, 3), key=lambda t: sum(u[1] for u in t))
for t in perms:
    print(tuple(u[0] for u in t))

This produces the same output (in the same order) as the above code. 这将产生与上述代码相同的输出(以相同的顺序)。


FWIW, here's an implementation of Rory Daulton' algorithm . FWIW,这是Rory Daulton算法的实现 Note that the output order is slightly different. 请注意,输出顺序略有不同。

 from itertools import permutations, combinations num = 5 for i in range(2, num): for u, v in combinations(range(i), 2): for t in permutations((u, v, i)): print(t) 

output 输出

 (0, 1, 2) (0, 2, 1) (1, 0, 2) (1, 2, 0) (2, 0, 1) (2, 1, 0) (0, 1, 3) (0, 3, 1) (1, 0, 3) (1, 3, 0) (3, 0, 1) (3, 1, 0) (0, 2, 3) (0, 3, 2) (2, 0, 3) (2, 3, 0) (3, 0, 2) (3, 2, 0) (1, 2, 3) (1, 3, 2) (2, 1, 3) (2, 3, 1) (3, 1, 2) (3, 2, 1) (0, 1, 4) (0, 4, 1) (1, 0, 4) (1, 4, 0) (4, 0, 1) (4, 1, 0) (0, 2, 4) (0, 4, 2) (2, 0, 4) (2, 4, 0) (4, 0, 2) (4, 2, 0) (0, 3, 4) (0, 4, 3) (3, 0, 4) (3, 4, 0) (4, 0, 3) (4, 3, 0) (1, 2, 4) (1, 4, 2) (2, 1, 4) (2, 4, 1) (4, 1, 2) (4, 2, 1) (1, 3, 4) (1, 4, 3) (3, 1, 4) (3, 4, 1) (4, 1, 3) (4, 3, 1) (2, 3, 4) (2, 4, 3) (3, 2, 4) (3, 4, 2) (4, 2, 3) (4, 3, 2) 

An abstracted, generator function variant of @Uvar's post: @Uvar的帖子的抽象的生成器函数变体:

Code

import itertools as it


def unique_permute(iterable, r=3, verbose=False):
    seen = set()
    for i, _ in enumerate(iterable):
        part = iterable[:i+1]
        if verbose: print("# Display 3-permutations of {} that haven't been displayed before".format(part))
        for p in it.permutations(part, r=r):
            if p not in seen:
                yield p
            seen.add(p)

Demo 演示版

lst = [0, 1, 2, 3, 4]
for p in unique_permute(lst, verbose=True):
    print("", p)

Output 输出量

# Display 3-permutations of [0] that haven't been displayed before
# Display 3-permutations of [0, 1] that haven't been displayed before
# Display 3-permutations of [0, 1, 2] that haven't been displayed before
 (0, 1, 2)
 (0, 2, 1)
 (1, 0, 2)
 (1, 2, 0)
 (2, 0, 1)
 (2, 1, 0)
# Display 3-permutations of [0, 1, 2, 3] that haven't been displayed before
 (0, 1, 3)
 (0, 2, 3)
 (0, 3, 1)
 (0, 3, 2)
 ...

There is a one liner for @Rory Daulton 's solution: @Rory Daulton的解决方案有一条衬里:

from itertools import *
a=[0,1,2,3,4]
print '\n'.join(['\n'.join([str(list(permutations(t)))  for t in list(combinations(a[:i+1],3)) if t not in list(combinations(a[:i],3))]) for i in range(2,len(a))])

Output: 输出:

 [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)] [(0, 1, 3), (0, 3, 1), (1, 0, 3), (1, 3, 0), (3, 0, 1), (3, 1, 0)] [(0, 2, 3), (0, 3, 2), (2, 0, 3), (2, 3, 0), (3, 0, 2), (3, 2, 0)] [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)] [(0, 1, 4), (0, 4, 1), (1, 0, 4), (1, 4, 0), (4, 0, 1), (4, 1, 0)] [(0, 2, 4), (0, 4, 2), (2, 0, 4), (2, 4, 0), (4, 0, 2), (4, 2, 0)] [(0, 3, 4), (0, 4, 3), (3, 0, 4), (3, 4, 0), (4, 0, 3), (4, 3, 0)] [(1, 2, 4), (1, 4, 2), (2, 1, 4), (2, 4, 1), (4, 1, 2), (4, 2, 1)] [(1, 3, 4), (1, 4, 3), (3, 1, 4), (3, 4, 1), (4, 1, 3), (4, 3, 1)] [(2, 3, 4), (2, 4, 3), (3, 2, 4), (3, 4, 2), (4, 2, 3), (4, 3, 2)] 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM