[英]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. 这将产生与上述代码相同的输出(以相同的顺序)。
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.