Двойная итерация в понимании списка

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

?? (Пожалуйста, только перечислите ответы на понимание, так как это то, что я хочу узнать).

Ответ 1

Ну и дела, я думаю, что нашел ответ: я не заботился о том, какая петля является внутренней, а какая внешней. Понимание списка должно быть таким:

[x for b in a for x in b]

чтобы получить желаемый результат, и да, одно текущее значение может быть итератором для следующего цикла.

Ответ 2

Чтобы ответить на свой вопрос своим предложением:

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

Ответ 3

Я надеюсь, что это поможет кому-то еще, так как 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?

Ответ 4

Порядок итераторов может казаться противоречащим интуиции.

Возьмем, например: [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)

Ответ 5

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

Ответ 6

Если вы хотите сохранить многомерный массив, нужно вложить скобки массива. см. пример ниже, где каждый добавляется к каждому элементу.

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

Ответ 7

Я чувствую, что это легче понять

[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 определяет, что мы хотим вернуть.