【问题标题】:List comprehension on a nested list?嵌套列表上的列表理解?
【发布时间】:2013-08-07 00:31:19
【问题描述】:

我有这个嵌套列表:

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

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

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 的总和。

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

【问题讨论】:

标签: python list nested list-comprehension


【解决方案1】:

以下是使用嵌套列表推导式执行此操作的方法:

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

这将为您提供一个列表列表,类似于您开始使用的列表,除了使用浮点数而不是字符串。如果你想要一个平面列表,那么你可以使用[float(y) for x in l for y in x]

【讨论】:

    【解决方案2】:

    下面是如何将嵌套 for 循环转换为嵌套列表理解:

    下面是嵌套列表理解的工作原理:

                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]
    

    【讨论】:

    • 超级好用!清楚地表明循环(从上到下)在生成器中从左到右排序。这并不明显,因为在 (f(x) for x in l) 中,for 循环等效项的第二行位于左侧。
    • @user48956 是的,我不认为将嵌套列表理解作为一个衬里非常直观。这种用法将是 imo 的反模式
    【解决方案3】:
    >>> 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]
    

    【讨论】:

      【解决方案4】:

      不确定您想要的输出是什么,但如果您使用列表推导式,则顺序遵循嵌套循环的顺序,而嵌套循环的顺序是倒数。所以我得到了我认为你想要的:

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

      原则是:使用与嵌套 for 循环相同的顺序。

      【讨论】:

      • 这应该是答案,因为有时我们不想将 iteratool 放在方括号中
      • 这可能不是正确的答案,因为它会输出一个非嵌套列表,但这是我一直在寻找的,特别是原理。谢谢!
      • 这是不正确的:[float(y)] 周围应该有括号
      【解决方案5】:

      我想分享列表推导的实际工作原理,尤其是嵌套列表推导:

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

      其实是一样的:

      new_list=[]
      for x in l:
          new_list.append(float(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]]
      

      【讨论】:

        【解决方案6】:

        我有一个类似的问题要解决,所以我遇到了这个问题。我对 Andrew Clark 和 narayan 的答案进行了性能比较,我想分享一下。

        两个答案之间的主要区别在于它们如何迭代内部列表。其中一个使用内置的map,而另一个使用列表理解。 Map function has slight performance advantage to its equivalent list comprehension if it doesn't require the use lambdas。因此,在这个问题的上下文中,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 在这种情况下比列表理解具有性能优势。如果您尝试转换为 intstr,这也适用。对于每个列表元素较少的少量列表,差异可以忽略不计。对于每个列表包含更多元素的较大列表,可能会喜欢使用 map 而不是列表解析,但这完全取决于应用程序的需求。

        不过,我个人认为列表理解比map 更具可读性和惯用性。它是 python 中的事实标准。通常人们在使用列表理解方面比map 更熟练和舒适(特别是初学者)。

        【讨论】:

          【解决方案7】:

          如果你不喜欢嵌套列表推导,你也可以使用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 是由于(misinformed ..)python3 中的更改导致生成器无法理解。
          【解决方案8】:

          这个问题可以不用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]]
          

          【讨论】:

          • 与@Andrew Clark 或 Harry Binswanger 的解决方案相比,lambdas 是否有任何性能优势(更普通的列表理解)?因为 lambdas 似乎更难阅读。
          • 在几乎任何其他通用编程语言中,我们都会使用链式map - 与您展示的内容一样。但是看看它在 python 中有多难看——尤其是考虑到上面的输出还不够:它是一个生成器而不是一个列表。甚至需要添加 more 样板文件list(list( .. ) ) 来完成图片。尝试fluentpy 和类似的库在一定程度上摆脱这个陷阱。
          【解决方案9】:

          是的,你可以用这样的代码做到这一点:

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

          【讨论】:

          • [float(y) for y in x for x in l] 这将导致一堆 100 的总和为 2400。
          【解决方案10】:

          在我看来,最好的方法是使用 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]
          

          【讨论】:

            【解决方案11】:

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

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

            【讨论】:

              【解决方案12】:

              如果需要扁平化列表:

              [y for x in l for y in x]
              

              如果需要嵌套列表(列表中的列表):

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

              【讨论】:

                【解决方案13】:
                    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 ]
                

                【讨论】:

                • 这似乎根本没有解决上面的问题。请注意,作为答案发布的所有内容都必须试图回答发布的问题。
                • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
                • 使用列表理解嵌套for循环,
                • 好的,很明显,这是一个回答问题的尝试。但是,这似乎是与 OP 中完全不同的场景,您甚至不处理嵌套列表作为输入,即使您更改您的建议几乎是 OP 已经尝试过的。另外,当问题是关于将字符串转换为浮点数时,我看不出有关卡片的示例有何帮助。
                • 忽略上面...您的评论帮助我大量解决了这个问题。谢谢
                猜你喜欢
                • 1970-01-01
                • 2021-02-13
                • 1970-01-01
                • 1970-01-01
                • 2011-12-24
                • 1970-01-01
                • 2021-11-17
                相关资源
                最近更新 更多