将列表中的每个项目重复另一个列表中指定的次数

Repeat each item in a list a number of times specified in another list

我有两个列表,xy:

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

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

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

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

最快、最有效、最 Pythonic 的方法是什么?

  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 returns 是一个可迭代对象,而不是一个列表。所以,如果你不想一次想要所有的元素,你可以从中一个一个地获取项目。如果 count 将是一个非常大的数字,这将是非常高效的内存,因为我们不会立即在内存中创建整个列表。我们按需生成值。

  4. 。您实际上可以在 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_iterablemap.

  5. 返回的可迭代对象中消耗每个可迭代对象的值

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

使用 for 循环很简单。

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

实现此目的的一种方法是使用 .elements() function of collections.Counter() along with 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]