Python 列表理解中的双重迭代

Python 列表理解中的双重迭代,python,list-comprehension,Python,List Comprehension,在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] ???(请只列出理解答案

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

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

天啊,我想我找到了答案:我没有足够注意哪个循环是内部的,哪个是外部的。列表应如下所示:

[x for b in a for x in b]

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

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

>>> [x for b in a for x in b] # Works fine
在您询问列表理解答案的同时,我还要指出优秀的itertools.chain()

来自itertools导入链的
>>
>>>列表(链从表(a))
>>>如果您使用的是python<2.6,请列出(chain(*a))35;

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]
>a=[[1,2],[3,4]]
>>>[x代表b中的x代表a中的b]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
名称错误:未定义名称“b”
>>>[x代表a中的b代表b中的x]
[1, 2, 3, 4]
>>>[x代表b中的x代表a中的b]
[3, 3, 4, 4]
我猜Python从左到右解析列表理解。这意味着将首先执行for的第一个
循环


第二个“问题”是
b
从列表中“泄漏”出去。在第一次成功理解列表后,我觉得这更容易理解

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

result: [1, 2, 3, 4]

我希望这能帮助其他人,因为
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?

迭代器的顺序似乎与直觉相反

举个例子:
[str(x)表示foo(i)中x的范围(3)中的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)

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

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

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

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

首先计算输入中x的
,得到输入的一个成员列表,然后Python遍历x中x的第二部分
,在此期间x值被它正在访问的当前元素覆盖,然后第一个
x
定义我们想要返回的内容。

这个内存技术对我帮助很大:

[…]

现在您可以考虑Return+Outer循环 作为唯一的RightOrder

了解以上内容后,即使对于3个循环,列表中的顺序也很简单:


对于另一个嵌套级别

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]


依此类推

此扁平化级别函数递归调用嵌套的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]

第一次尝试时,我永远也写不出双重理解。读入,原来是因为它的实现方式与你用英语阅读的方式相反。好消息是,它是一个逻辑上合理的实现,因此一旦您理解了结构,就很容易得到正确的结果

设a、b、c、d是连续嵌套的对象。对我来说,扩展列表理解的直观方法是模仿英语:

#有效
[f(b)代表a中的b]
#不起作用
[f(c)代表b中的c代表a中的b]
[f(c)代表g中的c(b)代表a中的b]
[f(d)代表c中的d代表b中的c代表a中的b代表b]
换句话说,你要从下往上阅读,即

#错误的逻辑
((d代表c中的d)代表b中的c)代表a中的b)
然而,这并不是Python实现嵌套列表的方式。相反,实现将第一个块视为完全独立的,然后将
for
s和
in
s从上到下(而不是从下到上)链接到单个块中,即

#正确的逻辑
d:(对于a中的b,对于b中的c,对于c中的d)
请注意,嵌套最深的级别(
对于c中的d
)距离列表中的最终对象最远(
d
)。原因是:

表单
[…for x…for y…]
嵌套,最后一个索引变化最快,就像嵌套for循环一样

使用Skam的文本示例,这一点变得更加清楚:

#单词:用于文本中的句子,用于句子中的单词
[文中逐字逐句]
#字母:用于文本中的句子,用于句子中的单词,用于单词中的字母
[逐字逐句逐句逐句逐句]
#信函:
#对于文本中的句子,如果len(句子)>2,
#对于句子[0]中的单词,
#对于单词中的字母if letter.is元音()
[如果len(句子)中的单词为文本中的句子字母>2[0]如果letter.is元音()中的单词为字母]

列表理解语法不是Python的亮点之一。@Glenn是的,它很容易让简单表达式变得复杂。Ew。我不确定这是否是列表理解的“常用”用法,但非常不幸的是,Python中的链接非常糟糕。如果在每个“for”之前都加上换行符,看起来非常干净。哇,这与我脑海中的想法完全相反。有趣的一点。我对此感到惊讶:
x='h
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]

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]