我想你可以按照你想要的顺序得到你的结果,如果你想到输出空间的图形遍历输出。你想要一个最接近第一遍,而itertools.product
函数是一个深度优先遍历。
尝试这样:
import heapq
def nearest_first_product(*sequences):
start = (0,)*len(sequences)
queue = [(0, start)]
seen = set([start])
while queue:
priority, indexes = heapq.heappop(queue)
yield tuple(seq[index] for seq, index in zip(sequences, indexes))
for i in range(len(sequences)):
if indexes[i] < len(sequences[i]) - 1:
lst = list(indexes)
lst[i] += 1
new_indexes = tuple(lst)
if new_indexes not in seen:
new_priority = sum(index * index for index in new_indexes)
heapq.heappush(queue, (new_priority, new_indexes))
seen.add(new_indexes)
输出示例:
for tup in nearest_first_product(range(1, 5), range(1, 4), range(1, 5)):
print(tup)
(1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(2, 1, 1)
(1, 2, 2)
(2, 1, 2)
(2, 2, 1)
(2, 2, 2)
(1, 1, 3)
(1, 3, 1)
(3, 1, 1)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
(2, 2, 3)
(2, 3, 2)
(3, 2, 2)
(1, 3, 3)
(3, 1, 3)
(3, 3, 1)
(1, 1, 4)
(2, 3, 3)
(3, 2, 3)
(3, 3, 2)
(4, 1, 1)
(1, 2, 4)
(2, 1, 4)
(4, 1, 2)
(4, 2, 1)
(2, 2, 4)
(4, 2, 2)
(3, 3, 3)
(1, 3, 4)
(3, 1, 4)
(4, 1, 3)
(4, 3, 1)
(2, 3, 4)
(3, 2, 4)
(4, 2, 3)
(4, 3, 2)
(3, 3, 4)
(4, 3, 3)
(4, 1, 4)
(4, 2, 4)
(4, 3, 4)
您可以通过在代码中改变了的new_priority
计算得到一堆略有不同的订单。当前版本使用平方笛卡尔距离作为优先级,但如果您想要(例如,将序列中的值合并到索引中,则可以使用其他值)。
如果你没有太在意(1, 1, 3)
是否到来之前(1, 2, 2)
(只要他们都来后(1, 1, 2)
,(1, 2, 1)
和(2, 1, 1)
),你很可能做一个广度优先遍历,而不是最近一。这会更简单一些,因为您可以使用常规队列(如collections.deque
)而不是优先级队列。
这种图遍历使用的队列表示此代码使用一定量的内存。但是,如果您必须在整理结果之前先完成结果,内存的数量会少很多。使用的最大内存与结果空间的表面积成正比,而不是其体积。
你究竟想要什么?那特别的订单,还是其他的订单? – miradulo
这个特定的顺序会很好,但我对任何改变“下一个排列”选择顺序的技术感兴趣。我希望生成的早期结果包含列表前面的大部分内容,但并不在乎解决方案是先生成113还是122,还是先生成211或112。 – dbn