English 中文(简体)
替换嵌套的for循环...还是不替换。
原标题:
  • 时间:2009-01-27 02:27:28
  •  标签:

我有一个脚本,可以循环遍历一系列的四个(或更少)字符的字符串。例如:

aaaa
aaab
aaac
aaad

如果可以像这样使用嵌套的循环来实现:

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 ,适用于任何数量的字符,您不必重复自己。并且非常易读。

问题回答

我打算提交我最易读但规模最小的答案 :)

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个字符的字符串。

通常我会删除这个答案,但如果您需要生成相同长度的字符串,则我仍然有点喜欢它。

Write for the programmer first - the computer second.
If it s clear and obvious to understand then its correct.

如果速度很重要,但编译器无法进行优化,如果你测量之后发现速度是问题所在 - 那么就要想出一个更快更聪明的方法!

我认为这不是件坏事,只要你理解(并记录:-))它。我不怀疑可能有更pythonic的方式或聪明的解决方案(使用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%。我认为这可能值得使用(再次,只要清楚地记录它正在尝试实现什么)。

@nosklo和@Triptych的解决方案产生了不同的结果:

>>> 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 ]

有许多算法可以生成一组的所有排列。您想要解决的是一个相关但不直接类似的问题。建议阅读:https://zh.wikipedia.org/wiki/%E6%8E%92%E5%88%97#.E7.94.A8.E7.A8.8B.E5.BA.8F.E7.94.9F.E6.88.90.E6.8E.92.E5.88.97

它并没有完全回答这个问题,但是它会返回给定最大长度和字母表中使用的字符的第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 很高,一些速度优化可能可以通过摆脱字符串拼接和在递归的每个级别重新计算 alphabetmaxlen-1 的长度来实现。非递归方法也可能有意义。





相关问题
热门标签