Python 使用itertools从某一点连续排列

Python 使用itertools从某一点连续排列,python,permutation,Python,Permutation,我有一大组排列,我想跑来跑去 from itertools import permutations perms = permutations([0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16], 6) 我正在使用一个简单的下一个调用来降低内存使用率 combination = perm.next() processing = True while processing: try: # using combination in code t

我有一大组排列,我想跑来跑去

from itertools import permutations
perms = permutations([0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16], 6)
我正在使用一个简单的下一个调用来降低内存使用率

combination = perm.next()
processing = True
while processing:
     try:
         # using combination in code then end by calling next
         # do_work(combination)   
         combination = perm.next()  
     except:
         print(combination) # (0,1,2,3,4,23)
         processing = False
这一切都很好。但我注意到,如果我停止它,我必须重新开始。 有没有办法从我跑的最后一点开始继续

例如:

(0,1,2,3,4,23)
下一步工作在哪里:

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


更新:许多伟大的解决方案!谢谢大家

您可以定义一个类来管理排列,其行为类似于列表:

from math import factorial
from collections.abc import Sequence
class Permutations(Sequence):
    
    def __init__(self,data,samples=None):
        self._data    = data
        self._samples = samples
        self._size    = 0
        self._lenData = 0

    def __len__(self):
        if self._lenData  != len(self._data):
            self._lenData  = len(self._data)
            samples        = min(self._lenData,self._samples or self._lenData)
            self.size      = factorial(self._lenData)//factorial(self._lenData-samples)
        return self.size
    
    def __getitem__(self,index):
        if isinstance(index,slice):
            return map(self.__getitem__,range(len(self))[index])
        scale     = len(self)
        remaining = list(self._data)
        result    = []
        for p in range(min(self._lenData,self._samples or self._lenData)):
            scale //= (len(self._data)-p)
            i,index = divmod(index,max(1,scale))
            result.append(remaining.pop(i))
        return tuple(result)
该类不使用额外的存储,只使用两个整数来管理大小更改。它甚至支持对引用列表进行即时更改

示例用法:

L = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16]
P = Permutations(L,6)

len(P)   # 5765760
P[6]     # (0, 1, 2, 3, 4, 11)

for perm in P[6:16]: print(perm)

(0, 1, 2, 3, 4, 11)
(0, 1, 2, 3, 4, 12)
(0, 1, 2, 3, 4, 13)
(0, 1, 2, 3, 4, 15)
(0, 1, 2, 3, 4, 16)
(0, 1, 2, 3, 5, 4)
(0, 1, 2, 3, 5, 6)
(0, 1, 2, 3, 5, 7)
(0, 1, 2, 3, 5, 8)
(0, 1, 2, 3, 5, 9)

for perm in P[-3:]: print(perm)

(16, 15, 13, 12, 11, 8)
(16, 15, 13, 12, 11, 9)
(16, 15, 13, 12, 11, 10)
若要从您停止的位置重新开始,您可以存储索引或排列。由于类的行为类似于列表,因此可以使用对分模块从已知排列中获取下一个索引:

from bisect import bisect_right

lastPermute = P[123]              # (0, 1, 2, 3, 16, 6)
i = bisect_right(P,lastPermute)
print(i)                          # 124
您甚至可以使用它获得随机排列,而无需在列表中生成所有排列:

random.choice(P)
(9, 7, 10, 5, 2, 4)    

random.sample(P,3)
[(15, 0, 13, 8, 10, 9), (9, 13, 3, 4, 8, 10), (1, 12, 0, 3, 6, 9)]

您可以将其pickle到文件中并重新加载以继续下一次运行

开始使用它:

>>> from itertools import permutations, islice
>>> perms = permutations([0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16], 6)
>>> *islice(perms, 3),
((0, 1, 2, 3, 4, 5), (0, 1, 2, 3, 4, 6), (0, 1, 2, 3, 4, 7))
保存状态以备以后使用(实际上会放入文件):


您可以跟踪已完成的运行次数,保存该数字,然后下次使用
itertools.islice(seq,start)
“我必须重新开始”-不正确。只需确保将
perm
保留在范围内,然后你就不必重新开始了。你有没有打算给我们展示一个所谓必须重新开始的演示?凯利,我能建议的是你重新阅读这个问题,因为除了你自己,其他人似乎都知道发生了什么。你似乎认为我的非最小片段存在排列。你跟next有麻烦吗?使用uuu next uuuuuuuu()无论如何,我很快就可以根据@BallpointBen的评论来解决这个问题。很好的类,但我需要数组的长度为6,最大值为16。我想
len
不会是一件很常见的事情,所以我建议将大小计算移到
\uuu len
中。另外,如果您定义了
\uuuuu len\uuuuu
\uuuuu getitem\uuuuuuu
,则不需要定义
\uuuuuu iter\uuuuuuu
。调整类以支持大量示例。@AlainT。仅供参考,您最近的更改破坏了您的代码。可能是中间保存,现已修复。非常好的解决方案+1.对我来说。。我也要试试这个
>>> import pickle
>>> pickled = pickle.dumps(perms)
>>> type(pickled), len(pickled)
(<class 'bytes'>, 135)
>>> restored = pickle.loads(pickled)
>>> *islice(restored, 3),
((0, 1, 2, 3, 4, 8), (0, 1, 2, 3, 4, 9), (0, 1, 2, 3, 4, 10))