Двойная итерация в понимании списка
В 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
определяет, что мы хотим вернуть.