单行嵌套for循环

140

我用Python写了一个矩阵转置的函数:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

在这个过程中,我意识到我并不完全理解单行嵌套for循环的执行方式。请通过回答以下问题帮助我理解:

  1. 这个for循环的执行顺序是什么?
  2. 如果我有一个三重嵌套的for循环,它的执行顺序是什么?
  3. 与未嵌套的for循环相等的内容是什么?

假设已知,

[ function(i,j) for i,j in object ]
  1. 为了使用这个for循环结构,对象必须是哪种类型?
  2. i和j被分配到对象元素的顺序是什么?
  3. 它可以通过不同的for循环结构模拟吗?
  4. 这个for循环可以与类似或不同结构的for循环嵌套吗?它会是什么样子?

欢迎提供额外信息。

5个回答

232

最好的信息来源是官方 Python 列表推导式教程。列表推导式与 for 循环几乎相同(确切地说,任何列表推导式都可以编写成 for 循环),但通常比使用 for 循环更快。

请看教程中这个更长的列表推导式(if 部分筛选推导式,只有通过 if 语句的部分才会传递到列表推导式的最终部分(这里为 (x, y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

这与嵌套的for循环完全相同(正如教程所说,注意for和if的顺序是相同的)。

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

列表解析和for循环的主要区别在于for循环的最后部分(你要做某事的地方)位于开头而不是结尾。

回答您的问题:

为了使用这个for循环结构,对象必须是什么类型?

一个可迭代对象。任何能生成(有限的)元素集合的对象。这些包括任何容器,如列表、集合、生成器等。

i和j被分配到对象的元素中的顺序是什么?

它们被分配的顺序与它们从每个列表中生成的顺序完全相同,就好像它们是在嵌套的for循环中(对于您的第一个列表解析,您将获得i的1个元素,然后是来自j的每个值,第二个元素进入i,然后是来自j的每个值,等等)。

可以用不同的for循环结构模拟吗?

可以,上面已经展示过了。

这个for循环可以与类似或不同的结构的for循环嵌套吗?它会是什么样子?

可以,但这不是一个好主意。在这里,例如,给出了一个字符列表的列表:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]

1
我想知道他们在双重嵌套中选择顺序的指导原则是什么。我发现另一种方式更自然(对于你的例子,先遍历y再遍历x)。我意识到这一点是在使用Python进行3年编程(虽然不是很深入),并且使用这些类型的循环!! - Thomas
@Thomas 我也觉得另一种方式更直观。我相信选择纯粹是为了方便。采用更直观的方式意味着必须处理未解决的符号,直到稍后在语句中找到它们。试着在纸上解析每个城市的香蕉店里每个香蕉皮。不太容易。但是另一种方式很简单。 - Pyjong

45

你可能对itertools.product感兴趣,它返回一个可迭代对象,该对象从您传递给它的所有可迭代对象中产生值元组。也就是说,itertools.product(A, B)会生成所有形如(a, b)的值,其中a的值来自Ab的值来自B。例如:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

这将打印:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

注意最后传递给 itertools.product 的参数是“内部”的。一般来说,itertools.product(a0, a1, ... an) 相当于 [(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]


4

首先,你的第一段代码并没有使用for循环,而是使用了列表推导

  1. 等价于

    for j in range(0, width): for i in range(0, height): m[i][j]

  2. 同样地,它通常会像嵌套的for循环一样从右到左嵌套。但是列表推导语法更为复杂。

  3. 我不确定这个问题在问什么


  1. Any iterable object that yields iterable objects that yield exactly two objects (what a mouthful - i.e [(1,2),'ab'] would be valid )

  2. The order in which the object yields upon iteration. i goes to the first yield, j the second.

  3. Yes, but not as pretty. I believe it is functionally equivalent to:

    l = list()
    for i,j in object:
        l.append(function(i,j))
    

    or even better use map:

    map(function, object)
    

    But of course function would have to get i, j itself.

  4. Isn't this the same question as 3?


Guido,Python的创始人,不鼓励使用map函数,以至于他曾考虑将其从Python中删除。 - JackofSpades
@JackofSpades 不会被删除。 - Beki

3

你可以使用zip函数在同一行中使用两个for循环。

代码:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

输出:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

因此,使用zip函数,我们可以使用两个for循环,也可以在同一行中迭代两个列表。


-6
以下代码是嵌套循环的最佳示例,当使用两个for循环时,请记住第一个循环的输出是第二个循环的输入。 在使用嵌套循环时,循环终止也非常重要。
for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8

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