关于python:在列表中创建重复项

Create duplicates in the list

我有

1
 list = [a, b, c, d]

1
numbers = [2, 4, 3, 1]

我想得到一个以下类型的列表:

1
new_list = [a, a, b, b, b, b, c, c, c, d]

这就是我目前为止所拥有的:

1
2
3
4
5
new_list=[]
for i in numbers:
    for x in list:
        for i in range(1,i+1):
            new_list.append(x)


有一种方法可以使用zip、字符串乘法和列表理解:

1
2
3
4
5
6
lst = ['a', 'b', 'c', 'd']
numbers = [2 , 4, 3, 1]

r = [x for i, j in zip(lst, numbers) for x in i*j]
print(r)
# ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

使用python时要注意名称的选择。像list这样的名称会使内置列表函数不可用。

如果lst中的项不是字符串,您可以简单地使用range上的嵌套理解来复制列表中的项。


嵌套列表理解工作:

1
2
3
4
5
L = ['a','b','c','d']
numbers = [2, 4, 3, 1]

>>> [x for x, number in zip(L, numbers) for _ in range(number)]
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

"子循环"for _ in range(number)重复值number次。这里,L可以容纳任何对象,而不仅仅是字符串。

例子:

1
2
3
4
L = [[1, 2, 3],'b','c', 'd']
numbers = [2, 4, 3, 1]
[x for x, number in zip(L, numbers) for _ in range(number)]
[[1, 2, 3], [1, 2, 3], 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

但这会使子列表变平:

1
2
[x for i, j in zip(L, numbers) for x in i*j]
[1, 2, 3, 1, 2, 3, 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

不完全是期望的结果。


作为任何对象(不仅是字符串)的一般方法,可以在生成器表达式中使用itertools.repeat()

1
2
def repeat_it(lst, numbers):
    return chain.from_iterable(repeat(i, j) for i, j in zip(lst, numbers))

演示:

1
2
3
4
5
6
7
8
9
10
11
In [13]: from itertools import repeat, chain

In [21]: lst=[5,4,6,0]

In [22]: list(repeat_it(lst, numbers))
Out[22]: [5, 5, 4, 4, 4, 4, 6, 6, 6, 0]

In [23]: lst=['a','b','c','d']

In [24]: list(repeat_it(lst, numbers))
Out[24]: ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

以下是3种主要方法的基准。请注意,最后一个选项仅适用于字符串:

1
2
3
4
5
6
7
8
9
10
11
12
In [49]: lst = lst * 1000

In [50]: numbers = numbers * 1000

In [51]: %timeit list(chain.from_iterable(repeat(i, j) for i, j in zip(lst, numbers)))
1 loops, best of 3: 8.8 s per loop

In [52]: %timeit [x for x, number in zip(lst, numbers) for _ in range(number)]
1 loops, best of 3: 12.4 s per loop

In [53]: %timeit [x for i, j in zip(lst, numbers) for x in i*j]
1 loops, best of 3: 7.2 s per loop

您可以使用numpy.repeat()作为另一个选项:

1
2
3
4
import numpy as np
np.repeat(lst, numbers).tolist()

# ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']


这是我的解决方案,只是添加一个不同的。

1
2
3
4
5
6
7
8
l = ['a', 'b', 'c', 'd']
n = [2, 4, 3, 1]
r = []
for i,v in enumerate(l):
    r += list(v*n[i])

>>> r
    ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']


无论a、b、c和d是变量还是字符串,这都可以工作:

1
2
3
4
5
6
7
8
9
10
a = 1
b = 2.0
c ="cheese"
d = ["c","a","k","e"]

lst = [a, b, c, d]
numbers = [2, 4, 3, 1]

# if len(lst) == len(numbers):
new_lst = [i for i, j in zip(lst, numbers) for k in range(j)]

您可能需要取消对if语句的注释(并缩进下面的行),以检查列表是否具有相同的长度,否则,新的清单将只包含与较短清单相同的项目。

这个、这个和关于嵌套列表理解的文档部分是值得阅读的。


如果你不确定列表理解是如何工作的,

1
2
3
4
5
6
7
8
myList=['a','b','c','d'] # not a good idea to use list as a name for your variable
numbers=[2,4,3,1]
new_list=[]
for i in range(len(myList)):    
    for j in range(numbers[i]):          
        new_list.append(myList[i])

print(new_list)


另一种处理循环的方法是:

1
2
3
4
new_list = []
for number, item in zip(numbers, l):
    for i in range(number):
        new_list.append(item)

现在我们有:

1
new_list = ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd']

假设两个列表的长度相同,第二个列表总是一个数字列表,这里有一个不使用zip或任何导入的解决方案:

1
2
3
4
lst = ['a', 'b', 'c', 'd']
numbers = [2,4,3,1]

result = sum([[lst[i]]*numbers[i] for i in range(len(lst))],[])