高效地连接大型列表元素

3
我想要制作一个元素列表,其中每个元素以4个数字开头和4个字母结尾,并包括所有可能的组合。这是我的代码。
import itertools

def char_range(c1, c2):
    """Generates the characters from `c1` to `c2`"""
    for c in range(ord(c1), ord(c2)+1):
        yield chr(c)


chars =list()
nums =list()
for combination in itertools.product(char_range('a','b'),repeat=4):
        chars.append(''.join(map(str, combination)))

for combination in itertools.product(range(10),repeat=4):
        nums.append(''.join(map(str, combination)))

c = [str(x)+y for x,y in itertools.product(nums,chars)]
for dd in c:
        print(dd)

这段代码运行良好,但当我使用更大范围的字符,比如(a-z),程序会占用CPU和内存,导致电脑无响应。那么我应该如何以更高效的方式完成此操作?

2
如果你有4个字母和4个数字,那么你会得到4'569'760'000(约4.5 G)种可能性。所以将其放入内存中非常困难。大约需要~256 GiB的内存来存储所有字符串(甚至没有考虑列表结构本身)。 - Willem Van Onsem
哦,我没有考虑到这种可能性:),那么这个问题可以通过某种缓冲解决吗?每个元素都被创建和打印,然后内存被释放? - MOHAMMAD RASIM
2
生成器方法可能会更好。例如使用 c = (str(x)+y for x,y in itertools.product(nums,chars)),也许对于 chars(和 nums)也可以采用类似的方法。 - Willem Van Onsem
你应该首先问自己为什么需要将所有可能的组合存储到内存中的列表中;逐个处理每个组合很可能更加高效。实际上,任何能够帮助你消除某些字符串的直觉也将有助于这个过程。 - Evan Weissburg
你为什么需要所有组合?如果你拥有它们,你认为你能做什么呢? - Peter Wood
我非常想看到一些输出。这将使您更快地了解自己正在做什么,从而简化操作。 - Stefan Pochmann
1个回答

1

itertools的文档说:"它大致相当于在生成器表达式中嵌套for循环"。因此,itertools.product永远不会占用过多内存,但如果您将其结果存储在列表中,则该列表会占用过多内存。因此:

for element in itertools.product(...):
    print element

没问题,但是

myList = [element for itertools.product(...)]

或者等价的循环。
for element in itertools.product(...):
    myList.append(element)

你希望使用itertools生成结果,但不想存储它们,而是在它们生成时直接使用。思考一下你代码中的这行:

c = [str(x)+y for x,y in itertools.product(nums,chars)]

考虑到nums和chars可能是巨大的列表,再建立一个包含它们所有组合的巨大列表肯定会使系统崩溃。如果你用生成器(只是产生值的函数)替换掉所有无法适应内存的列表,就像评论中提到的一样,内存就不再是问题了。这是完整代码。我基本上将你的字符和数字列表更改为生成器,并且摆脱了最终的c列表。
import itertools

def char_range(c1, c2):
    """Generates the characters from `c1` to `c2`"""
    for c in range(ord(c1), ord(c2)+1):
        yield chr(c)

def char(a):
    for combination in itertools.product(char_range(str(a[0]),str(a[1])),repeat=4):
        yield ''.join(map(str, combination))

def num(n):
    for combination in itertools.product(range(n),repeat=4):
        yield ''.join(map(str, combination))

def final(one,two):
    for foo in char(one):
        for bar in num(two):
            print str(bar)+str(foo)

现在让我们来询问每个 ['a','b'] 和范围(2)的组合是什么:
final(['a','b'],2)

产生以下结果:
0000aaaa
0001aaaa
0010aaaa
0011aaaa
0100aaaa
0101aaaa
0110aaaa
0111aaaa
1000aaaa
1001aaaa
1010aaaa
1011aaaa
1100aaaa
1101aaaa
1110aaaa
1111aaaa
0000aaab
0001aaab
0010aaab
0011aaab
0100aaab
0101aaab
0110aaab
0111aaab
1000aaab
1001aaab
1010aaab
1011aaab
1100aaab
1101aaab
1110aaab
1111aaab
0000aaba
0001aaba
0010aaba
0011aaba
0100aaba
0101aaba
0110aaba
0111aaba
1000aaba
1001aaba
1010aaba
1011aaba
1100aaba
1101aaba
1110aaba
1111aaba
0000aabb
0001aabb
0010aabb
0011aabb
0100aabb
0101aabb
0110aabb
0111aabb
1000aabb
1001aabb
1010aabb
1011aabb
1100aabb
1101aabb
1110aabb
1111aabb
0000abaa
0001abaa
0010abaa
0011abaa
0100abaa
0101abaa
0110abaa
0111abaa
1000abaa
1001abaa
1010abaa
1011abaa
1100abaa
1101abaa
1110abaa
1111abaa
0000abab
0001abab
0010abab
0011abab
0100abab
0101abab
0110abab
0111abab
1000abab
1001abab
1010abab
1011abab
1100abab
1101abab
1110abab
1111abab
0000abba
0001abba
0010abba
0011abba
0100abba
0101abba
0110abba
0111abba
1000abba
1001abba
1010abba
1011abba
1100abba
1101abba
1110abba
1111abba
0000abbb
0001abbb
0010abbb
0011abbb
0100abbb
0101abbb
0110abbb
0111abbb
1000abbb
1001abbb
1010abbb
1011abbb
1100abbb
1101abbb
1110abbb
1111abbb
0000baaa
0001baaa
0010baaa
0011baaa
0100baaa
0101baaa
0110baaa
0111baaa
1000baaa
1001baaa
1010baaa
1011baaa
1100baaa
1101baaa
1110baaa
1111baaa
0000baab
0001baab
0010baab
0011baab
0100baab
0101baab
0110baab
0111baab
1000baab
1001baab
1010baab
1011baab
1100baab
1101baab
1110baab
1111baab
0000baba
0001baba
0010baba
0011baba
0100baba
0101baba
0110baba
0111baba
1000baba
1001baba
1010baba
1011baba
1100baba
1101baba
1110baba
1111baba
0000babb
0001babb
0010babb
0011babb
0100babb
0101babb
0110babb
0111babb
1000babb
1001babb
1010babb
1011babb
1100babb
1101babb
1110babb
1111babb
0000bbaa
0001bbaa
0010bbaa
0011bbaa
0100bbaa
0101bbaa
0110bbaa
0111bbaa
1000bbaa
1001bbaa
1010bbaa
1011bbaa
1100bbaa
1101bbaa
1110bbaa
1111bbaa
0000bbab
0001bbab
0010bbab
0011bbab
0100bbab
0101bbab
0110bbab
0111bbab
1000bbab
1001bbab
1010bbab
1011bbab
1100bbab
1101bbab
1110bbab
1111bbab
0000bbba
0001bbba
0010bbba
0011bbba
0100bbba
0101bbba
0110bbba
0111bbba
1000bbba
1001bbba
1010bbba
1011bbba
1100bbba
1101bbba
1110bbba
1111bbba
0000bbbb
0001bbbb
0010bbbb
0011bbbb
0100bbbb
0101bbbb
0110bbbb
0111bbbb
1000bbbb
1001bbbb
1010bbbb
1011bbbb
1100bbbb
1101bbbb
1110bbbb
1111bbbb

这是你要寻找的确切结果。该结果的每个元素都是即时生成的,因此不会造成内存问题。现在你可以尝试并查看更大的操作,例如 final(['a','z'],10),它们对CPU友好。

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