如何遍历Python中所有单词,直到字母的排列?

时间:2019-04-15 17:31:07

标签: python iteration permutation itertools alphabet

对我来说,这似乎不是一个小问题,但令人惊讶的是,我在网上找不到任何有关它的信息。假设您有一个字母集(对我来说,是普通字母的前m个字母),并且您想有效地遍历该字母的所有单词(例如,以便对它们进行一些分析)。这在Python中很容易做到;做类似的事情

import itertools
alphabet = 'abcdefghijklmnopqrstuvwxyz'[0:m]
for l in range(0, 200):
    for word in itertools.product(alphabet, repeat=l):
        #foo

但是对于我的特定问题,当我对字符串进行分析时,很容易预测当我对字符串应用字母置换时答案将如何变化。速度在我的程序中至关重要,因此没有必要遍历所有所有单词;如果我可以对单词进行迭代直至字母的排列,那么我可以减少搜索空间,从而将速度降低len(alphabet)因数(在我的情况下,这也意味着我数据较少)在记忆中)。我看了一下,itertools中似乎没有这样的命令进行迭代

将一些代码拼凑起来很容易,这些代码在每个新单词长度的开头,将该长度的所有单词存储在列表中,针对字母的排列对列表进行筛选,然后使之列出要迭代的迭代器。问题在于,随着单词长度的增加,此列表将无法存储在内存中。谢谢。

1 个答案:

答案 0 :(得分:0)

我认为可以用少量的内存来做到这一点。我估计所需的内存与生成的字符串的长度成正比。

基本上,我们只希望不能将Caesar-Ciphered的字符串转换成在字典上较小的字符串。我没有正式的证明,但我怀疑这些字符串始终满足特定的属性:字符串中字符的首次出现从未出现在按字典顺序更大的字符之后。例如,"abbacb"满足此属性,因为第一个a出现在第一个b之前,而第一个b出现在第一个c之前。使用此属性,应该可以从最小的字符串开始递归地生成所有这样的字符串。

def gen_words(alphabet, size=None):
    if size is None:
        i = 0
        while True:
            yield from gen_words(alphabet, i)
            i += 1
    if size == 0:
        yield ""
    else:
        for s in gen_words(alphabet, size-1):
            #determine which characters are permissible.
            used_characters = sorted(set(s))
            #any character that has already been used is permissible.
            for c in used_characters:
                yield s + c
            #the lexicographically smallest unusued character is also permissible.
            if len(used_characters) < len(alphabet):
                yield s + alphabet[len(used_characters)]

g = gen_words("ab")
for i in range(20):
    print(next(g))

#or, to generate an infinite number os trings, use:
#for s in gen_words("ab"):
#    print(s)

结果:

a
aa
ab
aaa
aab
aba
abb
aaaa
aaab
aaba
aabb
abaa
abab
abba
abbb
aaaaa
aaaab
aaaba
aaabb