如何在Python中生成一个列表的排列,而不“移动”零。

9
使用 itertools 工具,我可以得到给定数字列表的所有可能排列,但是如果列表如下所示:
List=[0,0,0,0,3,6,0,0,5,0,0]

itertools 不知道遍历零是浪费功夫的,例如以下遍历结果会包含在结果中:

List=[0,3,0,0,0,6,0,0,5,0,0]

List=[0,3,0,0,0,6,0,0,5,0,0]

他们是相同的,但是 itertools 只是将第一个零(例如)移动到列表的第四个位置,反之亦然。
问题是:我如何只迭代一些选定的数字,而不管其他数字,比如零?可以使用或不使用 itertools

使用类似于output2 = list(set(output))的语句,其中output是从itertools获取的内容。 - barak manos
我需要在列表的所有位置上迭代一些数字,但保留零不变。 - V.Petretto
1
这就是你要的。(我的新的、第三种方法的答案) - jsbueno
3个回答

3
Voilá - 现在它可以工作了 - 在对“肉类”进行排列组合后,我进一步获取所有可能的“0”位置组合并为每个非0元素的排列组合得到一个“0位置”的可能集合中的一个排列。
from itertools import permutations, combinations

def permut_with_pivot(sequence, pivot=0):
    pivot_indexes = set()
    seq_len = 0
    def yield_non_pivots():
        nonlocal seq_len
        for i, item in enumerate(sequence):
            if item != pivot:
                yield item
            else:
                pivot_indexes.add(i)
        seq_len = i + 1

    def fill_pivots(permutation):
        for pivot_positions in combinations(range(seq_len), len(pivot_indexes)):
            sequence = iter(permutation)
            yield tuple ((pivot if i in pivot_positions else next(sequence)) for i in range(seq_len))

    for permutation in permutations(yield_non_pivots()):
        for filled_permutation in fill_pivots(permutation):
            yield filled_permutation

我使用了Python 3的“nonlocal”关键字-如果你仍在使用Python 2.7,你需要采取另一种方法,例如将seq_len作为一个列表,然后在内部函数中替换它的单个项。

我的第二次尝试(实际上工作的是第三次)

这是一种天真的方法,只是保留已经“看到”的排列的缓存-它节省了每个排列所做的工作,但不能减少生成所有可能排列的工作量。

from itertools import permutations

def non_repeating_permutations(seq):
    seen = set()
    for permutation in permutations(seq):
        hperm = hash(permutation)
        if hperm in seen:
            continue
        seen.add(hperm)
        yield permutation

1
现在您需要查看n的分区,其中n是原始列表中零的数量。非零元素的数量(k)也很重要,因为它们定义了允许的分区类型。例如,如果k = 3,如上面的示例,每个分区可以表示为k + 1个值的总和,但不能超过这个数。 - Ma0
1
@V.Petretto 但是你不想让它们被修复,对吗? - Ma0
不,我不想让它们被修复,让我写一个输出的例子:[0,0,1,0,8] [0,1,0,8,0] [1,0,8,0,0] [1,8,0,0,0] [8,0,1,0,0] 等等。 - V.Petretto
3
将英语翻译成中文。只返回翻译后的文本: - jsbueno
非常感谢! :) - V.Petretto

2

将每个结果添加到列表中。现在您将拥有每个可能的组合,然后执行以下操作:

list(set(your_big_list))

Set会将列表缩小到仅包含唯一的排列。我不确定这是否是你要解决的问题,或者你担心性能问题。无论如何,我刚刚注册了一个帐户,所以我想尝试做出一些贡献。


1
我看到你的方法唯一的问题是它在计算上效率低下。肯定有更好的方法。 - Ma0
是的,我试图解决的问题是性能和速度。使用大量数字列表,例如30个或更多,程序需要太长时间运行,浪费了很多工作,因此不够高效。 - V.Petretto
“Set”和“List”甚至不是Python内置的。也许你想说的是“list”和“set”。 - jsbueno
更不用说这会丢弃除了一个零以外的所有零(及其位置)以及任何其他重复的内容。 - jsbueno
是的,修复了那些大小写问题。 - raayan

0

你的问题不太清楚,但如果你想要列出排列组合而不在输出中包含0,可以按照以下方式进行:

from itertools import permutations
def perms( listy ):
    return permutations( [i for i in listy if i!=0])

1
我不认为这是他想要的,但这可以成为它的基础。现在,您可以将排列与0相结合,以生成更多组合,每个组合的长度都与原始列表相同 ☺ - Ma0
1
我需要输出中的0,但我不希望它成为排列的一部分。这样可以避免重复输出和浪费CPU工作。也许我可以创建一个零的基本列表,然后将排列好的数字插入其中? - V.Petretto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接