问题:列表理解中的双重迭代

在Python中,列表推导中可以有多个迭代器,例如

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

对于一些合适的序列a和b。我知道Python的列表推导的嵌套循环语义。

我的问题是:理解中的一个迭代器可以引用另一个吗?换句话说:我可以有这样的东西:

[x for x in a for a in b]

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

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

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

列表理解表达式将如何获得此结果:

[1,2,3,4]

?? (请只列出理解答案,因为这是我要查找的内容)。

In Python you can have multiple iterators in a list comprehension, like

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

for some suitable sequences a and b. I’m aware of the nested loop semantics of Python’s list comprehensions.

My question is: Can one iterator in the comprehension refer to the other? In other words: Could I have something like this:

[x for x in a for a in b]

where the current value of the outer loop is the iterator of the inner?

As an example, if I have a nested list:

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

what would the list comprehension expression be to achieve this result:

[1,2,3,4]

?? (Please only list comprehension answers, since this is what I want to find out).


回答 0

要根据自己的建议回答您的问题:

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

当您要求提供列表理解答案时,我还要指出出色的itertools.chain():

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

To answer your question with your own suggestion:

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

While you asked for list comprehension answers, let me also point out the excellent itertools.chain():

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

回答 1

我希望这对别人a,b,x,y有帮助,因为对我没有太大的意义!假设您有一个充满句子的文本,并且想要一个单词数组。

# Without list comprehension
list_of_words = []
for sentence in text:
    for word in sentence:
       list_of_words.append(word)
return list_of_words

我喜欢将列表理解理解为水平扩展代码。

尝试将其分解为:

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

例:

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> [word for sentence in text for word in sentence]
['Hi', 'Steve!', "What's", 'up?']

这也适用于生成器

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> gen = (word for sentence in text for word in sentence)
>>> for word in gen: print(word)
Hi
Steve!
What's
up?

I hope this helps someone else since a,b,x,y don’t have much meaning to me! Suppose you have a text full of sentences and you want an array of words.

# Without list comprehension
list_of_words = []
for sentence in text:
    for word in sentence:
       list_of_words.append(word)
return list_of_words

I like to think of list comprehension as stretching code horizontally.

Try breaking it up into:

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

Example:

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> [word for sentence in text for word in sentence]
['Hi', 'Steve!', "What's", 'up?']

This also works for generators

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> gen = (word for sentence in text for word in sentence)
>>> for word in gen: print(word)
Hi
Steve!
What's
up?

回答 2

e,我想我找到了答案:我对那个循环是内部的,哪个循环是外部的,没有足够的小心。列表理解应为:

[x for b in a for x in b]

为了获得期望的结果,是的,一个当前值可以作为下一个循环的迭代器。

Gee, I guess I found the anwser: I was not taking care enough about which loop is inner and which is outer. The list comprehension should be like:

[x for b in a for x in b]

to get the desired result, and yes, one current value can be the iterator for the next loop.


回答 3

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

举个例子: [str(x) for i in range(3) for x in foo(i)]

让我们分解一下:

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)

Order of iterators may seem counter-intuitive.

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

Let’s decompose it:

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)

回答 4

ThomasH已经添加了一个很好的答案,但是我想说明会发生什么:

>>> 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从列表理解中“泄漏”出去。在第一次成功理解清单之后b == [3, 4]

ThomasH has already added a good answer, but I want to show what happens:

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

I guess Python parses the list comprehension from left to right. This means, the first for loop that occurs will be executed first.

The second “problem” of this is that b gets “leaked” out of the list comprehension. After the first successful list comprehension b == [3, 4].


回答 5

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

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

If you want to keep the multi dimensional array, one should nest the array brackets. see example below where one is added to every element.

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

回答 6

这种记忆技术对我有很大帮助:

[ <RETURNED_VALUE> <OUTER_LOOP1> <INNER_LOOP2> <INNER_LOOP3> ... <OPTIONAL_IF> ]

现在,你可以想想[R E打开+ Ø uter环作为唯一的[R飞行Ø刻申

综上所述,即使对于3个循环,列表中的顺序也很容易:


c=[111, 222, 333]
b=[11, 22, 33]
a=[1, 2, 3]

print(
  [
    (i, j, k)                            # <RETURNED_VALUE> 
    for i in a for j in b for k in c     # in order: loop1, loop2, loop3
    if i < 2 and j < 20 and k < 200      # <OPTIONAL_IF>
  ]
)
[(1, 11, 111)]

因为上面只是一个:

for i in a:                         # outer loop1 GOES SECOND
  for j in b:                       # inner loop2 GOES THIRD
    for k in c:                     # inner loop3 GOES FOURTH
      if i < 2 and j < 20 and k < 200:
        print((i, j, k))            # returned value GOES FIRST

对于迭代一个嵌套列表/结构,技术是相同的:a从问题出发:

a = [[1,2],[3,4]]
[i2    for i1 in a      for i2 in i1]
which return [1, 2, 3, 4]

互相嵌套的水平

a = [[[1, 2], [3, 4]], [[5, 6], [7, 8, 9]], [[10]]]
[i3    for i1 in a      for i2 in i1     for i3 in i2]
which return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

等等

This memory technic helps me a lot:

[ <RETURNED_VALUE> <OUTER_LOOP1> <INNER_LOOP2> <INNER_LOOP3> ... <OPTIONAL_IF> ]

And now you can think about Return + Outer-loop as the only Right Order

Knowing above, the order in list comprehensive even for 3 loops seem easy:


c=[111, 222, 333]
b=[11, 22, 33]
a=[1, 2, 3]

print(
  [
    (i, j, k)                            # <RETURNED_VALUE> 
    for i in a for j in b for k in c     # in order: loop1, loop2, loop3
    if i < 2 and j < 20 and k < 200      # <OPTIONAL_IF>
  ]
)
[(1, 11, 111)]

because the above is just a:

for i in a:                         # outer loop1 GOES SECOND
  for j in b:                       # inner loop2 GOES THIRD
    for k in c:                     # inner loop3 GOES FOURTH
      if i < 2 and j < 20 and k < 200:
        print((i, j, k))            # returned value GOES FIRST

for iterating one nested list/structure, technic is the same: for a from the question:

a = [[1,2],[3,4]]
[i2    for i1 in a      for i2 in i1]
which return [1, 2, 3, 4]

for one another nested level

a = [[[1, 2], [3, 4]], [[5, 6], [7, 8, 9]], [[10]]]
[i3    for i1 in a      for i2 in i1     for i3 in i2]
which return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

and so on


回答 7

我觉得这更容易理解

[row[i] for row in a for i in range(len(a))]

result: [1, 2, 3, 4]

I feel this is easier to understand

[row[i] for row in a for i in range(len(a))]

result: [1, 2, 3, 4]

回答 8

另外,您可以对当前访问的输入列表的成员该成员中的元素使用相同的变量。但是,这甚至可能使它(清单)更加难以理解。

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定义了我们要返回的内容。

Additionally, you could use just the same variable for the member of the input list which is currently accessed and for the element inside this member. However, this might even make it more (list) incomprehensible.

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

First for x in input is evaluated, leading to one member list of the input, then, Python walks through the second part for x in x during which the x-value is overwritten by the current element it is accessing, then the first x defines what we want to return.


回答 9

这个flatten_nlevel函数递归调用嵌套的list1以隐蔽到一个级别。试试看

def flatten_nlevel(list1, flat_list):
    for sublist in list1:
        if isinstance(sublist, type(list)):        
            flatten_nlevel(sublist, flat_list)
        else:
            flat_list.append(sublist)

list1 = [1,[1,[2,3,[4,6]],4],5]

items = []
flatten_nlevel(list1,items)
print(items)

输出:

[1, 1, 2, 3, 4, 6, 4, 5]

This flatten_nlevel function calls recursively the nested list1 to covert to one level. Try this out

def flatten_nlevel(list1, flat_list):
    for sublist in list1:
        if isinstance(sublist, type(list)):        
            flatten_nlevel(sublist, flat_list)
        else:
            flat_list.append(sublist)

list1 = [1,[1,[2,3,[4,6]],4],5]

items = []
flatten_nlevel(list1,items)
print(items)

output:

[1, 1, 2, 3, 4, 6, 4, 5]

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。