关于python:列表理解中的双重迭代

Double Iteration in List Comprehension

在python中,在一个列表理解中可以有多个迭代器,比如

1
[(x,y) for x in a for y in b]

对于一些合适的序列A和B,我知道Python列表理解的嵌套循环语义。

我的问题是:理解中的一个迭代器可以引用另一个吗?换言之:我可以要这样的东西吗?

1
[x for x in a for a in b]

外部循环的当前值在哪里是内部循环的迭代器?

例如,如果我有一个嵌套列表:

1
a=[[1,2],[3,4]]

为了达到这个结果,列表理解表达式是什么:

1
[1,2,3,4]

??(请只列出理解答案,因为这是我想知道的)。


用你自己的建议来回答你的问题:

1
>>> [x for b in a for x in b] # Works fine

当你要求列出理解答案时,我还要指出优秀的itertools.chain():

1
2
3
>>> from itertools import chain
>>> list(chain.from_iterable(a))
>>> list(chain(*a)) # If you're using python < 2.6

哎呀,我想我找到了一个答案:我对哪一个环是内部的,哪一个环是外部的考虑不够。列表理解应该如下:

1
[x for b in a for x in b]

为了得到所需的结果,是的,一个当前值可以是下一个循环的迭代器。


我希望这对其他人有帮助,因为a,b,x,y对我没有多大意义!假设你有一个充满句子的文本,你想要一组单词。

1
2
3
4
5
6
# Without list comprehension
list_of_words = []
for sentence in text:
    for word in sentence:
       list_of_words.append(word)
return list_of_words

我喜欢把列表理解看作是水平扩展代码。

试着把它分成:

1
2
# List Comprehension
[word for sentence in text for word in sentence]


迭代器的顺序似乎有违直觉。

例如:[str(x) for i in range(3) for x in foo(i)]

让我们分解它:

1
2
3
4
5
6
7
8
9
10
11
12
def foo(i):
    return i, i + 0.5

[str(x)
    for i in range(3)
        for x in foo(i)
]

# is same as
for i in range(3):
    for x in foo(i):
        yield str(x)


托马斯已经补充了一个很好的答案,但我想展示一下会发生什么:

1
2
3
4
5
6
7
8
9
10
>>> a = [[1, 2], [3, 4]]
>>> [x for x in b for b in a]
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
NameError: name 'b' is not defined

>>> [x for b in a for x in b]
[1, 2, 3, 4]
>>> [x for x in b for b in a]
[3, 3, 4, 4]

我猜python从左到右解析列表理解。这意味着,发生的第一个for循环将首先执行。

第二个"问题"是,b从列表理解中"泄露"。在第一次成功的列表理解之后,1(2)。


如果要保留多维数组,应嵌套数组括号。请参见下面的示例,其中每个元素都添加一个元素。

1
2
3
4
5
6
7
>>> a = [[1, 2], [3, 4]]

>>> [[col +1 for col in row] for row in a]
[[2, 3], [4, 5]]

>>> [col +1 for row in a for col in row]
[2, 3, 4, 5]


此外,对于当前访问的输入列表的成员和此成员内的元素,可以使用相同的变量。然而,这甚至可能使它更难以理解。

1
2
input = [[1, 2], [3, 4]]
[x for x in input for x in x]

首先对for x in input进行评估,得到输入的一个成员列表,然后python遍历第二部分for x in x,在此期间x值被它正在访问的当前元素覆盖,然后第一个x定义我们要返回的内容。


我觉得这更容易理解

1
2
3
[row[i] for row in a for i in range(len(a))]

result: [1, 2, 3, 4]