【问题标题】:Repeat each item in a list a number of times specified in another list重复列表中的每个项目在另一个列表中指定的次数
【发布时间】:2015-10-28 03:34:40
【问题描述】:

我有两个列表,xy

>>> x = [2, 3, 4]
>>> y = [1, 2, 3]

我想用这些来创建一个新列表。新列表将使x 中的每个元素重复y 中相应元素指定的次数。因此,期望的输出是

>>> new_list
[2, 3, 3, 4, 4, 4]

new_list 中元素的顺序对我来说并不重要。 list 也不是很重要——任何序列类型都可以。

最快、最有效、最符合 Python 的方法是什么?

【问题讨论】:

  • 要求“最快、最高效、最 Pythonic 的方式”就像要求“最快、最安全、最紫色的车”。虽然最符合 Python 风格的方式是最快的,这很好,但过分关心它是否是最快的方式是最不符合 Python 标准的。

标签: python list repeat


【解决方案1】:

numpy 的 repeat 函数完成工作:

>>> import numpy as np
>>> x = [2, 3, 4]
>>> y = [1, 2, 3]
>>> np.repeat(x, y)
array([2, 3, 3, 4, 4, 4])

【讨论】:

    【解决方案2】:
    1. 你可以像这样使用列表推导

      >>> x = [2, 3, 4]
      >>> y = [1, 2, 3]
      >>> [item for item, count in zip(x, y) for i in range(count)]
      [2, 3, 3, 4, 4, 4]
      

      在这里,我们将 zip xy 组合在一起,以便 x 中的元素及其对应的 y 中的计数分组为单个元组。然后,我们迭代 count 的项目数以生成相同的项目。

    2. 如果您在x 中的对象是不可变的,那么您可以创建相同的count 副本并将它们放在一个列表中,就像这样

      >>> [i for item, count in zip(x, y) for i in [item] * count]
      [2, 3, 3, 4, 4, 4]
      
    3. 你可以懒惰地做同样的事情,itertools.repeat,像这样

      >>> from itertools import chain, repeat
      >>> chain.from_iterable((repeat(item, count) for item, count in zip(x,y)))
      <itertools.chain object at 0x7fabe40b5320>
      >>> list(chain.from_iterable((repeat(item, cnt) for item, cnt in zip(x,y))))
      [2, 3, 3, 4, 4, 4]
      

      请注意,chain 返回的是可迭代的,而不是列表。因此,如果您不想一次获得所有元素,则可以从中逐个获取项目。如果count 将是一个非常大的数字,这将是高效的内存,因为我们不会立即在内存中创建整个列表。我们按需生成值。

    4. Thanks ShadowRanger。您实际上可以在xy 上应用repeat 并得到这样的结果

      >>> list(chain.from_iterable(map(repeat, x, y)))
      [2, 3, 3, 4, 4, 4]
      

      在这里,map 函数将 xy 中的值一一应用到 repeat。所以,map 的结果将是

      >>> list(map(repeat, x, y))
      [repeat(2, 1), repeat(3, 2), repeat(4, 3)]
      

      现在,我们使用chain.from_iterable 来使用map 返回的可迭代对象中的每个可迭代对象的值。

    【讨论】:

    • chain 方法可以简化为:list(chain.from_iterable(map(repeat, x, y)))(如果这是 Py2,可能想做from future_builtins import map,在 Py3 上是不必要的)。
    • 也可以使用list(chain.from_iterable(starmap(repeat, izip(x, y))))izip -&gt; zip 用于python3.x ...不知道这是否更好...
    • @mgilson,任何使用starmap的机会都必须被视为Pythonic
    【解决方案3】:

    简单地使用for 循环。

    >>> x = [2, 3, 4]
    >>> y = [1, 2, 3]
    >>> final = []
    >>> for index, item in enumerate(y):
            final.extend([x[index]]*item)
    

    【讨论】:

    • for i, j in zip(x, y): final += [i] * j
    【解决方案4】:

    实现此目的的一种方法是使用collections.Counter().elements() 函数和zip。例如:

    >>> from collections import Counter
    
    >>> x = [2, 3, 4]
    >>> y = [1, 2, 3]
    
    # `.elements()` returns an object of `itertool.chain` type, which is an iterator.
    # in order to display it's content, here type-casting it to `list` 
    >>> list(Counter(dict(zip(x,y))).elements())
    [2, 3, 3, 4, 4, 4]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-08
      • 2021-12-22
      • 2020-01-01
      • 1970-01-01
      • 2022-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多