嵌套列表上的列表理解?


219

我有这个嵌套列表:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

现在,我要做的是将列表中的每个元素转换为float。我的解决方案是这样的:

newList = []
for x in l:
  for y in x:
    newList.append(float(y))

但这可以使用嵌套列表理解来完成吗?

我所做的是:

[float(y) for y in x for x in l]

但是结果是一堆100的总数为2400。

任何解决方案,解释将不胜感激。谢谢!


15
想汇整清单?
Greg Hewgill 2013年

@GregHewgill:OP没有回复,但是基于他们接受的答案,他们似乎想保留嵌套。
smci

Answers:


317

这是使用嵌套列表推导的方法:

[[float(y) for y in x] for x in l]

这将为您提供一个列表列表,类似于您开始时使用的列表,但使用浮点数而不是字符串。如果您想要一个固定列表,则可以使用[float(y) for x in l for y in x]


190

以下是将嵌套的for循环转换为嵌套列表理解的方法:

enter image description here

以下是嵌套列表推导的工作方式:

            l a b c d e f
                  
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ]
In [2]: for a in l:
   ...:     for b in a:
   ...:         for c in b:
   ...:             for d in c:
   ...:                 for e in d:
   ...:                     for f in e:
   ...:                         print(float(f))
   ...:                         
1.0

In [3]: [float(f)
         for a in l
   ...:     for b in a
   ...:         for c in b
   ...:             for d in c
   ...:                 for e in d
   ...:                     for f in e]
Out[3]: [1.0]

对于您的情况,将是这样的。

In [4]: new_list = [float(y) for x in l for y in x]

21
超级有用!明确说明循环(自上而下)在生成器中从左到右排序。这并不明显,因为(f(x) for x in l)将for循环等效项的第二行放在左侧。
user48956 '18

这似乎是我真正想到的一个解释,谢谢!
Douglas Plumley

48
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]

42

不确定所需的输出是什么,但是如果您使用列表推导,则顺序遵循嵌套循环的顺序,而嵌套循环的顺序是向后的。所以我得到了我想要的东西:

[float(y) for x in l for y in x]

原理是:使用与嵌套循环相同的顺序来写出来。


这应该是答案,因为有些时候我们不想将iteratool
放在

1
这可能不是正确的答案,因为它会输出非嵌套列表,但这正是我一直在寻找的,尤其是原理。谢谢!
Rodrigo E. Principe

4

由于我来这里不晚,但我想分享列表理解的实际工作原理,尤其是嵌套列表理解:

New_list= [[float(y) for x in l]

实际上与:

New_list=[]
for x in l:
    New_list.append(x)

现在嵌套列表理解:

[[float(y) for y in x] for x in l]

与;

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

输出:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

3

如果您不喜欢嵌套列表推导,也可以使用map函数,

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]

您的代码生成地图对象而不是列表: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] 但是添加一个额外的调用以按预期运行它: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperfect

@pixelperfect,这是由于(错误通知..)更改而python3导致生成器无法理解的。
javadba

3

我有一个类似的问题要解决,所以遇到了这个问题。我对安德鲁·克拉克(Andrew Clark)和纳拉扬(narayan)的答案进行了性能比较,我想分享一下。

两个答案之间的主要区别是它们如何遍历内部列表。其中一个使用内置地图,而另一个使用列表推导。如果不需要使用lambdas,则Map函数与其等效的列表理解相比在性能上会有一点优势。所以在这个问题的背景下map应比列表理解稍好。

让我们做一个性能基准,看看它是否真的是真的。我使用python 3.5.0版执行所有这些测试。在第一组测试中,我希望每个列表的元素数量保持为10,列表数量从10-100,000不等

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

在此处输入图片说明

在下一组测试中,我希望将每个列表的元素数量增加到100个

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

在此处输入图片说明

让我们采取一个勇敢的步骤并将列表中的元素数修改为1000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

在此处输入图片说明

从这些测试中,我们可以得出结论,map在这种情况下,与列表理解相比,它具有性能优势。如果您要强制转换为int或,这也适用str。对于少量列表且每个列表元素较少的列表,差异可以忽略不计。对于每个列表具有更多元素的较大列表,可能要使用map而不是列表理解,但这完全取决于应用程序的需求。

但是我个人认为列表理解比map。这是python中的事实上的标准。通常,人们比使用列表理解更熟练和更舒适(特别是初学者)map


2

是的,您可以使用以下代码进行操作:

l = [[float(y) for y in x] for x in l]

[float(y) for y in x for x in l]这将导致与2400的总和一串100米的的
男孩派斯莫

2

无需使用for循环即可解决此问题,只需单行代码即可。在lambda函数中使用嵌套地图也可以在这里使用。

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

输出列表如下:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

1
lambdas是否比说@Andrew Clark或Harry Binswanger的解决方案(更容易理解列表)具有任何性能优势?由于lambda似乎更难阅读。
StefanJCollier '17

0

我认为做到这一点的最佳方法是使用python的itertools软件包。

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]

0

是的,您可以执行以下操作。

[[float(y) for y in x] for x in l]

-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

这可以通过列表理解来实现:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

1
这似乎根本没有解决这个问题。请注意,所有发布为答案的内容都必须尝试回答发布到的问题。
Baum mit Augen

尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。也请尽量不要在代码中加入解释性注释,这会降低代码和解释的可读性!
菲诺18'Mar

使用列表理解嵌套循环
ADITYA KUMAR

1
好的,显然,这是一个回答问题的尝试。但是,这似乎是与OP中完全不同的情况,您甚至没有将嵌套列表作为输入处理,即使您更改了您的建议几乎是OP已经尝试过的。另外,当问题涉及将字符串转换为浮点型时,我看不到关于卡片的示例有什么帮助。
Baum mit Augen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.