在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]
?? (请仅列出理解答案,因为这是我想要找到的)。
答案 0 :(得分:136)
用你自己的建议回答你的问题:
>>> [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
答案 1 :(得分:106)
我希望这可以帮助别人,因为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]
答案 2 :(得分:103)
哎呀,我想我发现了一个问题:我没有足够关注哪个循环是内部的,哪个是外部的。列表理解应该是:
[x for b in a for x in b]
获得所需的结果,是的,一个当前值可以作为下一个循环的迭代器。
答案 3 :(得分:37)
迭代器的顺序可能看似违反直觉。
例如:[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)
答案 4 :(得分:18)
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]
之后。
答案 5 :(得分: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]
答案 6 :(得分:6)
这种记忆技术对我有很大帮助:
[ <RETURNED_VALUE> <OUTER_LOOP1> <INNER_LOOP2> <INNER_LOOP3> ... <OPTIONAL_IF> ]
现在您可以考虑 R eturn + O 计算机循环 作为唯一的 R 权限 O 订单
知道了这些,列表中的顺序对于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]
以此类推
答案 7 :(得分:3)
此外,您可以对输入列表的成员使用相同的变量,该成员当前访问此成员中的元素和。但是,这甚至可能使它更难以理解()。
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
定义了我们想要返回的内容。
答案 8 :(得分:3)
在我第一次尝试时,我永远无法写出双重列表理解。阅读PEP202,结果证明它的实现方式与您用英语阅读的方式相反。好消息是它是一个逻辑上合理的实现,所以一旦你理解了结构,就很容易做好。
设 a, b, c, d 是连续嵌套的对象。对我来说,扩展列表理解的直观方式是模仿英语:
# works
[f(b) for b in a]
# does not work
[f(c) for c in b for b in a]
[f(c) for c in g(b) for b in a]
[f(d) for d in c for c in b for b in a]
换句话说,你会从下往上阅读,即
# wrong logic
(((d for d in c) for c in b) for b in a)
然而,这不是 Python 实现嵌套列表的方式。相反,该实现将第一个块视为完全独立的,然后将 for
和 in
从上到下(而不是自下而上)链接在一个块中,即
# right logic
d: (for b in a, for c in b, for d in c)
请注意,最深的嵌套级别 (for d in c
) 距离列表中的最终对象 (d
) 最远。原因在于from Guido himself:
表单 [... for x... for y...]
嵌套,最后一个索引变化最快,就像嵌套 for 循环一样。
使用 Skam 的文本示例,这变得更加清晰:
# word: for sentence in text, for word in sentence
[word for sentence in text for word in sentence]
# letter: for sentence in text, for word in sentence, for letter in word
[letter for sentence in text for word in sentence for letter in word]
# letter:
# for sentence in text if len(sentence) > 2,
# for word in sentence[0],
# for letter in word if letter.isvowel()
[letter for sentence in text if len(sentence) > 2 for word in sentence[0] for letter in word if letter.isvowel()]
答案 9 :(得分:2)
我觉得这更容易理解
[row[i] for row in a for i in range(len(a))]
result: [1, 2, 3, 4]
答案 10 :(得分:1)
此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]