Python:嵌套的“for”循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41764579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 01:34:36  来源:igfitidea点击:

Python: nested 'for' loops

pythonfor-loopnested

提问by 098799

I'd like to go through all n-digit numbers such that second digit of the number is always lower or equal to the first, third is lower or equal to the second etc. I can get this by writing a horrible code such as:

我想遍历所有 n 位数字,以便该数字的第二个数字始终低于或等于第一个,第三个低于或等于第二个等等。我可以通过编写一个可怕的代码来获得它,例如:

for i in range(10):
    for j in range(i+1):
        for k in range(j+1):

etc., but with 10-digit numbers my code starts looking horrible, and also that's a lot of writing, and indentation get horrible if I want to commend few of those. Is there a nice, concise way of getting this?

等等,但是对于 10 位数字,我的代码开始看起来很糟糕,而且写了很多东西,如果我想推荐其中的一些,缩进会变得很糟糕。有没有一个不错的,简洁的方法来获得这个?

Edit: just so that people know why I'm bothering with this, https://projecteuler.net/problem=74has me check numbers from 1 to one milion. Unfortunately, It's not as straightforward as I thought -- numbers with leading zeros are treated differently than the ones with zeros inside, so some additional magic had to be performed. Anyway, thanks to all for insightful suggestions.

编辑:只是为了让人们知道我为什么要为此烦恼,https://projecteuler.net/problem=74 让我检查从 1 到一百万的数字。不幸的是,这并不像我想象的那么简单——带有前导零的数字与内部带有零的数字的处理方式不同,因此必须执行一些额外的魔术。无论如何,感谢所有有见地的建议。

回答by Stefan Pochmann

Could use itertools:

可以使用itertools

>>> for comb in itertools.combinations_with_replacement(range(9, -1, -1), 3):
        print comb

(9, 9, 9)
(9, 9, 8)
(9, 9, 7)
(9, 9, 6)
...
(4, 0, 0)
(3, 3, 3)
(3, 3, 2)
(3, 3, 1)
(3, 3, 0)
(3, 2, 2)
(3, 2, 1)
(3, 2, 0)
(3, 1, 1)
(3, 1, 0)
(3, 0, 0)
(2, 2, 2)
(2, 2, 1)
(2, 2, 0)
(2, 1, 1)
(2, 1, 0)
(2, 0, 0)
(1, 1, 1)
(1, 1, 0)
(1, 0, 0)
(0, 0, 0)


Or recursively, appending more and more digits until enough, which can more directly produce intobjects instead of digit tuples (not sure whether that's what you actually need):

或者递归地,附加越来越多的数字直到足够,这可以更直接地生成int对象而不是数字元组(不确定这是否是您真正需要的):

def build(enough, prefix=0):
    if prefix >= enough:
        print(prefix)
        return
    for digit in range(prefix % 10 + 1) if prefix else range(1, 10):
        build(enough, prefix * 10 + digit)

Demo (note it leaves out "000", not sure whether you'd want that anyway):

演示(注意它省略了“ 000”,不确定你是否想要):

>>> n = 3
>>> build(10**(n-1))
100
110
111
200
210
211
220
221
222
300
310
311
320
321
322
330
331
332
333
400
410
411
420

回答by hiro protagonist

this an approach using itertools:

这是一种使用的方法itertools

from itertools import combinations_with_replacement

N = 3

for kji in combinations_with_replacement((str(i) for i in range(10)), N):
    print(''.join(reversed(kji)))

note that the order is not the same as in your original approach.

请注意,顺序与您原来的方法不同。

i recently had a simliar question...

我最近有一个类似的问题...

回答by Thomas Andrews

A simple recursive approach:

一个简单的递归方法:

def ordered_digits_generator(numDigits,min=1,max=9):
    for first in range(min,max+1):
        if numDigits == 1:
             yield first
        else:
             addend = first*10**(numDigits-1)
             for rest in ordered_digits(numDigits-1,min=0,max=first):
                 yield addend+rest

Then called via:

然后通过以下方式调用:

for number in ordered_digits_generator(10):
    print number

works as expected.

按预期工作。

The mathematician's approach

数学家的方法

The itertools package already has logic which essentially already implements this recursion. Presumably better than we can, with significant testing. So we can use it as follows:

itertools 包已经有逻辑,基本上已经实现了这个递归。通过重要的测试,大概比我们能做的更好。所以我们可以这样使用它:

import itertools
def ordered_digits_combo(numDigits):
    exponent = [10**i for i in range(0,numDigits)]

    for subset in itertools.combinations(range(0,numDigits+9),numDigits):
        if subset[numDigits-1]>numDigits-1:
            v = 0
            for i in range(0,numDigits):
                v += exponent[i]*(subset[i]-i)
            yield v

Given an ordered subset a[0]<a[1]<...<a[n-1]of {0,1,...,n+8}, we pick the number with the ithdigit from the right equal to a[i]-i. We have to exclude the case a[n-1]==n-1because that consists of he number with all zeros.

给定一个有序子集a[0]<a[1]<...<a[n-1]{0,1,...,n+8},我们选择的数量与我从右边等于位a[i]-i。我们必须排除这种情况,a[n-1]==n-1因为它由全零的数字组成。

回答by brian_o

I implemented @iFlo's suggestion as commented originally. It's not hyper efficient but it certainly doesn't take ages.

我按照最初的评论实施了@iFlo 的建议。它的效率不是很高,但肯定不会花费很长时间。

def digit_test(n):
    while n > 9:
        if (n % 100 / 10) < (n % 10): return False
        n /= 10
    return True

# under a second to construct a list of all numbers below 1000000 meeting the criteria
candidates = [x for x in xrange(1,1000000) if digit_test(x)]

# should be 8001 elements, consistent with other algorithms
print len(candidates)

回答by Brandon

I would probably implement this recursively:

我可能会递归地实现这个:

def generate(max, digits):
    for d in range(max + 1):
        if digits == 1:
            yield d
        else:
            first = d * 10**(digits-1)
            for n in generate(d, digits - 1):
                yield first + n

The output:

输出:

In : list(generate(3, 3))
Out:
[0,
 100,
 110,
 111,
 200,
 210,
 211,
 220,
 221,
 222,
 300,
 310,
 311,
 320,
 321,
 322,
 330,
 331,
 332,
 333]