Itertools停止连续重复的字符

时间:2016-04-28 12:44:01

标签: python itertools

我编写了以下代码,使用A,T,G和C的组合制作长度为20个字符的所有字符串。

但是,我想连续避免使用3个以上相同的字符,所以我添加了一个if函数来检查这个。问题是,这是在itertools代码之后,所以它有点慢。我想知道是否有办法使用itertools生成这个结果而不必运行itertools然后运行if函数?

import sys
import itertools
import re

x = ["A","T","G","C"]
for i in itertools.product(x, repeat=20):
        i = "".join(i)
        if re.search(r"(\w)\1\1",i):
                continue
        else:
                sys.stdout.write(i)

1 个答案:

答案 0 :(得分:2)

从表面上看,问题似乎是在问:

  

如何在不必先构建整个列表的情况下过滤这个庞大的字符串列表?

答案是:你已经在做了! itertools中的事物产生了延迟生成的延迟生成的序列。因此,您现有的代码会生成数十亿字符串的大量列表。

但是你可能想问一个可能更有趣的问题:

  

如果我通过生成所有字符串生成无三元组的字符串并过滤掉三元组中的字符串,我的代码必须做额外的工作,因为生成的大多数字符串都会包含三元组。假设字符串是按字典顺序生成的;然后他们的第一个4 ** 17将开始AAA,我们真的应该能够跳过所有这些。我们怎样才能做得更好?

不幸的是,如果你想这个那么你必须编写自己的代码才能做到这一点; itertools并未提供此类"模式过滤产品"功能。

它可能看起来像这样:

# generate all n-tuples with the property that their k-th element
# is one of the things returned by successors(initial (k-1)-tuple).
# So e.g. the first element is one of the things returned by
# successors(()).
def restricted_tuples(successors, n):
    assert(n>=0)
    if n==0:
        for t in successors(()): yield (t,)
    else:
        for start in restricted_tuples(successors, n-1):
            for t in successors(start): yield start+(t,)

def successors_no_triples(start, alphabet):
    if len(start)<2 or start[-1] != start[-2]:
        for t in alphabet: yield t
    else:
        banned = start[-1]
        for t in alphabet:
            if t != banned: yield t

print([''.join(x) for x in restricted_tuples(lambda start: successors_no_triples(start,'ABC'), 5)])

最后的print仅供参考。如果您想打印原始提问者的所有数十亿字符串的情况,您最好迭代restricted_tuples生成的序列,并分别对每个字符串进行字符串化和打印。

顺便说一句,具有此属性的4个字母上的长度为20的序列的数量证明为415,289,569,968。如果你试图全部生成它们,你会等待一段时间,特别是如果你真的想要任何事情。