简体   繁体   English

迭代列表中没有两个重复的行

[英]Iterate over lists without two duplicates in a row

I would like to iterate over lists of integers in a similar way to:我想以类似于以下方式迭代整数列表:

itertools.product(range(n), repeat=5)

If n = 3 this gives:如果 n = 3 这给出:

[(0, 0, 0, 0, 0),
 (0, 0, 0, 0, 1),
 (0, 0, 0, 0, 2),
 (0, 0, 0, 1, 0),
 (0, 0, 0, 1, 1),
 (0, 0, 0, 1, 2),
 (0, 0, 0, 2, 0),
 (0, 0, 0, 2, 1),
 (0, 0, 0, 2, 2),
 (0, 0, 1, 0, 0),
[...]

However I want only those tuples that don't have the same number twice in a row.但是,我只想要那些连续两次不具有相同数字的元组。 So (0,0,1,0,0) would be excluded as would many others.所以 (0,0,1,0,0) 会像许多其他人一样被排除在外。

How can you do this?你怎么能做到这一点?

It's probably more efficient to generate the sequences without consecutive duplicates yourself, rather than generating all of the sequences with itertools.product and filtering them.自己生成没有连续重复的序列可能更有效,而不是使用itertools.product生成所有序列并对其进行过滤。 I'd use a recursive generator like this:我会使用这样的递归生成器:

def gen(seq, n, prefix=()):
    if n == 0:
        yield prefix
        return

    for x in seq:
        if not prefix or x != prefix[-1]:
             yield from gen(seq, n-1, prefix+(x,))

example output:示例输出:

>>> list(gen(range(3), 5))
[(0, 1, 0, 1, 0),
 (0, 1, 0, 1, 2),
 (0, 1, 0, 2, 0),
 (0, 1, 0, 2, 1),
 (0, 1, 2, 0, 1),
 (0, 1, 2, 0, 2),
 (0, 1, 2, 1, 0),
 (0, 1, 2, 1, 2),
 (0, 2, 0, 1, 0),
 (0, 2, 0, 1, 2),
 (0, 2, 0, 2, 0),
 (0, 2, 0, 2, 1),
 (0, 2, 1, 0, 1),
 (0, 2, 1, 0, 2),
 (0, 2, 1, 2, 0),
 (0, 2, 1, 2, 1),
 (1, 0, 1, 0, 1),
 (1, 0, 1, 0, 2),
 (1, 0, 1, 2, 0),
 (1, 0, 1, 2, 1),
 (1, 0, 2, 0, 1),
 (1, 0, 2, 0, 2),
 (1, 0, 2, 1, 0),
 (1, 0, 2, 1, 2),
 (1, 2, 0, 1, 0),
 (1, 2, 0, 1, 2),
 (1, 2, 0, 2, 0),
 (1, 2, 0, 2, 1),
 (1, 2, 1, 0, 1),
 (1, 2, 1, 0, 2),
 (1, 2, 1, 2, 0),
 (1, 2, 1, 2, 1),
 (2, 0, 1, 0, 1),
 (2, 0, 1, 0, 2),
 (2, 0, 1, 2, 0),
 (2, 0, 1, 2, 1),
 (2, 0, 2, 0, 1),
 (2, 0, 2, 0, 2),
 (2, 0, 2, 1, 0),
 (2, 0, 2, 1, 2),
 (2, 1, 0, 1, 0),
 (2, 1, 0, 1, 2),
 (2, 1, 0, 2, 0),
 (2, 1, 0, 2, 1),
 (2, 1, 2, 0, 1),
 (2, 1, 2, 0, 2),
 (2, 1, 2, 1, 0),
 (2, 1, 2, 1, 2)]

Try:尝试:

output = [
          lst for lst in itertools.product(range(3), repeat=3) 
          if not any(i==j for i, j in zip(lst[:-1],lst[1:]))
         ]

You can use a comprensive list with a guard:您可以使用带有警卫的综合列表:

n = 3
repeat = 5
[l for l in itertools.product(range(n), repeat=repeat) if not any(l[n-1] == l[n] for n in range(1, repeat))]

This will filter out any line with at least one value identical to the previous one.这将过滤掉至少有一个与前一行相同的值的任何行。

If you want to use higher-level functions you can check that the number of groups in a groupby is that same as the repeat.如果您想使用更高级别的功能,您可以检查 groupby 中的组数是否与重复相同。

n = 3
r = 5
out_gen = filter(
    lambda x: len(tuple(itertools.groupby(x)))==r, 
    itertools.product(range(n), repeat=r)
)

Here's another take on the recursive generator approach that is based on excluding the value from the calling recursion rather than passing down the whole result:这是对递归生成器方法的另一种看法,它基于从调用递归中排除值而不是传递整个结果:

def comb(A,n,x=None):
    yield from ([v]+r for v in A if v!=x for r in comb(A,n-1,v)) if n else [[]]

Output:输出:

for p in comb(range(3),5):print(p)
[0, 1, 0, 1, 0]
[0, 1, 0, 1, 2]
[0, 1, 0, 2, 0]
[0, 1, 0, 2, 1]
[0, 1, 2, 0, 1]
[0, 1, 2, 0, 2]
[0, 1, 2, 1, 0]
[0, 1, 2, 1, 2]
[0, 2, 0, 1, 0]
[0, 2, 0, 1, 2]
[0, 2, 0, 2, 0]
[0, 2, 0, 2, 1]
[0, 2, 1, 0, 1]
[0, 2, 1, 0, 2]
[0, 2, 1, 2, 0]
[0, 2, 1, 2, 1]
[1, 0, 1, 0, 1]
[1, 0, 1, 0, 2]
[1, 0, 1, 2, 0]
[1, 0, 1, 2, 1]
[1, 0, 2, 0, 1]
[1, 0, 2, 0, 2]
[1, 0, 2, 1, 0]
[1, 0, 2, 1, 2]
[1, 2, 0, 1, 0]
[1, 2, 0, 1, 2]
[1, 2, 0, 2, 0]
[1, 2, 0, 2, 1]
[1, 2, 1, 0, 1]
[1, 2, 1, 0, 2]
[1, 2, 1, 2, 0]
[1, 2, 1, 2, 1]
[2, 0, 1, 0, 1]
[2, 0, 1, 0, 2]
[2, 0, 1, 2, 0]
[2, 0, 1, 2, 1]
[2, 0, 2, 0, 1]
[2, 0, 2, 0, 2]
[2, 0, 2, 1, 0]
[2, 0, 2, 1, 2]
[2, 1, 0, 1, 0]
[2, 1, 0, 1, 2]
[2, 1, 0, 2, 0]
[2, 1, 0, 2, 1]
[2, 1, 2, 0, 1]
[2, 1, 2, 0, 2]
[2, 1, 2, 1, 0]
[2, 1, 2, 1, 2]

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

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