替换嵌套的 For 循环...或不替换
-
20-08-2019 - |
题
我有一个脚本循环遍历一系列四个(或更少)字符串。例如:
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)
这种循环嵌套是一件坏事吗?如果是的话,完成我正在做的事情的更好方法是什么?
解决方案
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为任意数量的字符,而不必重复自己。而且是相当的可读性。
其他提示
我要提交我的回答是最可读的,最不可扩展的:)
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字符的字符串。
一般情况下我删除这个答案,但我还是有点喜欢它,如果你需要生成相同长度的字符串。
写为程序员第一 - 计算机第二结果 如果它是明确而清晰的了解那么它是正确的。
如果速度事项和编译器不反正优化它,如果你衡量它,它是问题 - !然后想更快更聪明的方式
我不认为这是一件坏事,只要你明白(和:-)它的文档。我不怀疑有可能是一个更Python的方式或聪明的解决方案(与lambda表达式或诸如此类的东西),但我一直看好的可读性上聪明。
由于必须生成的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.84这个版本大约需要2.25个时间单元所以它的26%的速度。我认为这可能保证其使用(再一次的,只要它的记录清楚什么它试图达到)。
>>> 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']
有用于生成一组的每个排列许多算法。你想要的这里是一个相关的问题,但不能直接analagous。 推荐阅读
这并不完全回答这个问题,但是这将返回字母表对于给定的最大长度和字符组合n
th使用:
#!/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
的长度。非递归的方法可能是有意义了。