我有一个循环遍历一系列四个(或更少)字符串的脚本。例如:
aaaa
aaab
aaac
aaad
如果能够使用嵌套的for循环实现它,那么:
chars = string.digits + string.uppercase + string.lowercase
for a in chars:
print '%s' % a
for b in chars:
print '%s%s' % (a, b)
for c in chars:
print '%s%s%s' % (a, b, c)
for d in chars:
print '%s%s%s%s' % (a, b, c, d)
这种循环是一种坏事,如果是这样,那么什么是更好的方式来完成我正在做的事情?
答案 0 :(得分:15)
import string
import itertools
chars = string.digits + string.letters
MAX_CHARS = 4
for nletters in range(MAX_CHARS):
for word in itertools.product(chars, repeat=nletters + 1):
print (''.join(word))
这将打印您正在寻找的所有 15018570
字词。如果您想要更多/更少的单词,只需更改MAX_CHARS
变量即可。对于任意数量的字符,它仍然只有两个for
s,你不必重复自己。而且很可读。
答案 1 :(得分:6)
我要将我的答案提交为最具可读性和最不可扩展性的答案:)
import string
chars = [''] + list(string.lowercase)
strings = (a+b+c+d for a in chars
for b in chars
for c in chars
for d in chars)
for string in strings:
print string
编辑:实际上,这是不正确的,因为它会产生所有长度<4的字符串的重复。从chars
数组中删除空字符串只会生成4个字符串。
通常我会删除这个答案,但如果你需要生成相同长度的字符串,我仍然会喜欢它。
答案 2 :(得分:4)
首先为程序员写 - 计算机第二 如果明白且明显地理解那么它是正确的。
如果速度很重要且编译器无论如何都不优化它,如果你测量它并且这是问题 - 那么想想一个更快更聪明的方法!
答案 3 :(得分:3)
如果您了解(并记录:-),我认为这不是一件坏事。我不怀疑可能有更多的pythonic方式或聪明的解决方案(使用lambdas或诸如此类别)但我总是喜欢可读性而不是聪明。
由于您必须生成1,2-,3-和4个字符“单词”的所有可能性,因此此方法与任何方法一样好。我不确定你需要多长时间才能有效地生成(非常大致)1400万行输出(但可能每个解决方案都有这个问题)。
预先计算公共前缀可能会提高速度,但您最好先测量它以进行检查(始终检查,从不假设):
chars = string.digits + string.uppercase + string.lowercase
for a in chars:
print a
for b in chars:
ab = '%s%s' % (a, b)
print ab
for c in chars:
abc = '%s%s' % (ab, c)
print abc
for d in chars:
print '%s%s' % (abc, d)
编辑:我实际上做了一些基准测试(使用Windows-Python 2.6.1) - 这个版本需要大约2.25个时间单位,而原始的2.84个,所以它快了26%。我认为这可能值得使用(再次,只要它清楚地记录了它试图实现的目标)。
答案 4 :(得分:2)
@nosklo's和@Triptych's解决方案会产生不同的结果:
>>> list(map(''.join, itertools.chain.from_iterable(itertools.product("ab",
... repeat=r) for r in range(4)))) # @nosklo's
['', 'a', 'b', 'aa', 'ab', 'ba', 'bb', 'aaa', 'aab', 'aba', 'abb', 'baa', 'bab', 'bba', 'bbb']
>>> ab = ['']+list("ab")
>>> list(map(''.join, (a+b+c for a in ab for b in ab for c in ab)))
['', 'a', 'b', 'a', 'aa', 'ab', 'b', 'ba', 'bb', 'a', 'aa', 'ab', 'aa', 'aaa', 'aab', 'ab', 'aba', 'abb', 'b', 'ba', 'bb', 'ba', 'baa', 'bab', 'bb', 'bba', 'bbb']
这里修改了@ Triptych的解决方案,产生与@nosklo相同的输出:
>>> ab = "ab"
>>> list(map(''.join, itertools.chain([''], ab, (a+b for a in ab for b in ab),
... (a+b+c for a in ab for b in ab for c in ab))))
['', 'a', 'b', 'aa', 'ab', 'ba', 'bb', 'aaa', 'aab', 'aba', 'abb', 'baa', 'bab', 'bba', 'bbb']
答案 5 :(得分:1)
有许多算法可用于生成集合的每个排列。你想要的是一个相关的问题,但不是直接的分类。 Suggested Reading
答案 6 :(得分:1)
它并没有完全回答这个问题,但是这将返回给定最大长度的n
组合以及要使用的字母表中的字符:
#!/usr/bin/python
def nth_combination(n, maxlen=4, alphabet='abc'):
"""
>>> print ','.join(nth_combination(n, 1, 'abc') for n in range(3))
a,b,c
>>> print ','.join(nth_combination(n, 2, 'abc') for n in range(12))
a,aa,ab,ac,b,ba,bb,bc,c,ca,cb,cc
>>> import string ; alphabet = string.ascii_letters + string.digits
>>> print ','.join(nth_combination(n, 4, alphabet) for n in range(16))
a,aa,aaa,aaaa,aaab,aaac,aaad,aaae,aaaf,aaag,aaah,aaai,aaaj,aaak,aaal,aaam
>>> print ','.join(nth_combination(n, 4, alphabet)
... for n in range(0, 14000000, 10**6))
a,emiL,iyro,mKz2,qWIF,u8Ri,zk0U,Dxav,HJi9,LVrM,P7Ap,UjJ1,YvSE,2H1h
"""
if maxlen == 1:
return alphabet[n]
offset, next_n = divmod(n, 1 + len(alphabet)**(maxlen-1))
if next_n == 0:
return alphabet[offset]
return alphabet[offset] + nth_combination(next_n-1, maxlen-1, alphabet)
if __name__ == '__main__':
from doctest import testmod
testmod()
当然,只有当你需要随机访问这些组合而不是总是遍历它们时,这当然才有意义。
如果maxlen
很高,则可以实现某些速度优化,例如通过删除字符串连接并在递归的每个级别重新计算alphabet
和maxlen-1
的长度。非递归方法也可能有意义。