【问题标题】:Break down this list using list comprehension使用列表推导分解此列表
【发布时间】:2012-03-04 22:58:12
【问题描述】:

我想知道是否有一个很好的 Pythonic 方法来分解这个列表:

['1,2,3', '22', '33']

进入列表:

['1','2','3','22','33']

使用列表推导?

【问题讨论】:

    标签: python list list-comprehension


    【解决方案1】:

    使用列表推导,它看起来像这样:

    >>> L = ['1,2,3', '22', '33']
    >>> [x for s in L for x in s.split(",")]
    ['1', '2', '3', '22', '33']
    

    【讨论】:

    • 其实我比我更喜欢这个!不知道我是怎么忘记这个解决方案的。
    • 嵌套列表理解适用于这个简单的示例,但对于更一般的情况(例如,使用子嵌套),它们不能泛化和链式化
    • +1 这是在列表推导中非常合理地使用嵌套 for 循环。
    【解决方案2】:

    我不会使用sum,因为它会重复连接并创建大量副本。我会这样做:

    >>> import itertools
    >>> l =  ['1,2,3', '22', '33']
    >>> list(itertools.chain.from_iterable(s.split(',') for s in l))
    ['1', '2', '3', '22', '33']
    

    确实,对于非常短的列表,它会稍微慢一些:

    >>> %timeit sum((s.split(',') for s in l), [])
    100000 loops, best of 3: 2.38 us per loop
    >>> %timeit list(itertools.chain.from_iterable(s.split(',') for s in l))
    100000 loops, best of 3: 3.51 us per loop
    

    但是对于长列表,它方式比使用sum快:

    >>> l =  ['1,2,3', '22', '33'] * 500
    >>> %timeit sum((s.split(',') for s in l), [])
    100 loops, best of 3: 6.22 ms per loop
    >>> %timeit list(itertools.chain.from_iterable(s.split(',') for s in l))
    1000 loops, best of 3: 664 us per loop
    

    不过,其实我更喜欢wim 的回答。快速测试表明它是所有情况下启动速度最快的:

    >>> l =  ['1,2,3', '22', '33'] 
    >>> %timeit [x for s in l for x in s.split()]
    1000000 loops, best of 3: 1.45 us per loop
    >>> l =  ['1,2,3', '22', '33'] * 500
    >>> %timeit [x for s in l for x in s.split()]
    1000 loops, best of 3: 559 us per loop
    

    【讨论】:

    • 我认为chain.from_iterable 解决方案的最大优势不是速度,而是在我看来它比 sum 更直接..
    • @Voo,是的,我同意!但我喜欢 Python 的一件事是,当我进行上述测试时,我发现更直接的选择也是更有效的选择。
    • 这是真正定义python的好方法!我自己从来没有这样表述过,但现在你这么说——是的,绝对如此。将 python 与 c++ 进行比较会使这种差异非常明显。
    【解决方案3】:

    由于已经使用 sum() 函数作为解决方案发布了两个答案,我想我会提供另一种方式,使用 itertools.chain

    from itertools import chain
    x = ['1,2,3', '22', '33']
    result = chain.from_iterable(i.split(',') for i in x)
    
    print result
    #<itertools.chain object at 0x1004b5e10>
    

    chain 命令的结果是一个生成器。因此,您可以循环遍历结果,或将其转换为另一种序列类型(元组、列表、集合......)

    【讨论】:

    • 您也可以使用chain.from_iterable() 代替chain(*...)。更明确的东西......
    • @stranac,事实上,这不仅仅是明确的问题; * 运算符将生成器转换为元组,从而破坏了使用元组的意义。
    • @jdi 如果只显示 from_iterable 方法,这个答案会更好。星型拆包发生在堆栈上,因此无法很好地扩展。
    【解决方案4】:

    分解你的问题。你永远看不到如何一次解决整个问题,而且 Python 从来没有简单的内置解决方案来解决整个问题。弄清楚你的问题中最基本的部分是什么,并且每个部分通常都有简单的直接解决方案。然后结合解决方案。另外,不要指望你可以在问题上挥动一个神奇的口号,比如“列表理解”,让它消失。弄清楚您的解决方案需要做什么,然后考虑列表推导式是否可以做到这一点。

    你有一个字符串'1,2,3'。您需要将其拆分为多个字符串的列表,其中包含由逗号分隔的原始字符串位:

    >>> help(str.split)
    Help on method_descriptor:
    
    split(...)
        S.split([sep [,maxsplit]]) -> list of strings
    
        Return a list of the words in the string S, using sep as the
        delimiter string.  If maxsplit is given, at most maxsplit
        splits are done. If sep is not specified or is None, any
        whitespace string is a separator and empty strings are removed
        from the result.
    
    >>> '1,2,3'.split(',')
    ['1', '2', '3']
    >>> '3'.split(',')
    ['3']
    

    现在,您有一个字符串列表,并且您希望将每个字符串拆分为一个列表,如上:

    >>> [s.split(',') for s in ['1','2','3','22','33']]
    [['1'], ['2'], ['3'], ['22'], ['33']]
    

    现在您已经有了一个列表列表。您需要一个包含列表列表中每个列表元素的列表。操作“给我列表列表中的每个列表中的每一件事”非常自然地映射到列表推导,如下所示:

    >>> list_of_lists = [[1, 2, 3], ['a', 'b', 'c']]
    >>> [thing for alist in list_of_lists for thing in alist]
    [1, 2, 3, 'a', 'b', 'c']
    

    把它们放在一起:

    >>> [bit for string in ['1','2','3','22','33'] for bit in string.split(',')]
    ['1', '2', '3', '22', '33']
    

    这就是您使用列表推导解决此问题的方法。其他答案中还有许多其他潜在的解决方案,这些解决方案在技术方面更好。但是,如果您是 Python 新手,学习整个标准库(尤其是功能强大但抽象的东西,例如 itertools)会很困难,而且您不必觉得必须这样做。从长远来看,熟悉基础知识将为您提供更多帮助。

    【讨论】:

    • +1 建议 OP 如何将问题分解为更简单的子问题。
    【解决方案5】:

    这是我能想到的最简单的解决方案。

    它将sum() 与生成器表达式一起使用,因为您实际上并不需要创建子列表。

    >>> a = ['1,2,3', '22', '33']
    >>> sum((s.split(',') for s in a), [])
    ['1', '2', '3', '22', '33']
    

    【讨论】:

    • 这是对 sum 的不当使用。连续的连接是 O(n**2) 的性能。 @senderle 的代码好多更好。
    【解决方案6】:

    一个简单的方法是:

    >>> lst = ['1,2,3', '22', '33']
    >>> res = []
    >>> for x in lst:
    ...     res.extend(x.split(','))
    >>> res
    ['1', '2', '3', '22', '33']
    

    虽然它不使用列表推导,但我不明白为什么你会在这种情况下使用它。

    【讨论】:

    • 它也比其他解决方案更快:itertools、sum、nexted listcomps
    【解决方案7】:

    你可以这样做(假设你的列表叫做 l):

    sum([s.split(',') for s in l], [])
    

    【讨论】:

      猜你喜欢
      • 2014-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多