[英]Expand list with identical elements
假设我有以下嵌套列表:
initial_list = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
我想把它变成以下内容:
desired_list = [[1, 1, 1, 2, 2, 2, 3, 3, 3],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[7, 7, 7, 8, 8, 8, 9, 9, 9]]
如果我不关心订单,我可以做类似的事情
new_list = [sorted(x*3) for x in initial_list]
但是,顺序应与initial_list
的顺序保持一致。 我能做的最好的事情是将每个元素放在一个列表中并将其乘以 3(任意数),然后加入生成的inner_list
:
multiplied_list = [[[element]*3 for element in inner_list] for inner_list in initial_list]
desired_list = [[element for element_list in inner_list for element in element_list] for inner_list in multiplied_list]
(在人类理解的两个列表中)
是否有更易于理解/足够/pythonic 的方式来执行此操作?
您可以只使用以下列表理解。 请注意,我的initial_list
与 OP 中的不同,以证明保留了顺序。
代码:
>>> initial_list = [[1, 3, 2], [4, 5, 6], [7, 8, 9]]
>>> [[x for x in sl for _ in range(3)] for sl in initial_list]
[[1, 1, 1, 3, 3, 3, 2, 2, 2],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[7, 7, 7, 8, 8, 8, 9, 9, 9]]
或者,在您的示例中为 sorted 函数添加一个键:
>>> [sorted(x*3, key=x.index) for x in initial_list]
[[1, 1, 1, 3, 3, 3, 2, 2, 2],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[7, 7, 7, 8, 8, 8, 9, 9, 9]]
具有不同 n*n 列表大小的方法的时间比较:
使用perfplot生成 - 重现代码:
from itertools import chain
from functools import reduce
import perfplot
from copy import deepcopy
import numpy as np
import random
def shuffle(x):
random.shuffle(x)
return x
def cdjb(initial_list):
return [[x for x in sl for _ in range(3)] for sl in initial_list]
def aurora_sorted(initial_list):
return [sorted(x*3, key=x.index) for x in initial_list]
def aurora_list_comp(initial_list):
return [[element for element_list in inner_list for element in element_list] for inner_list in [[[element]*3 for element in inner_list] for inner_list in initial_list]]
def kederrac(initial_list):
new_list = deepcopy(initial_list)
for l in new_list:
for j in range(0, 3*len(l), 3):
l[j: j + 1] = [l[j]] * 3
return new_list
def alain_chain(initial_list):
return [list(chain(*(i3 for i3 in zip(*[sl]*3)))) for sl in initial_list]
def alain_reduce(initial_list):
return [list(reduce(lambda a,e:a+[e]*3,sl,[]))for sl in initial_list]
def alain_zip(initial_list):
return [[i for i3 in zip(*[sl]*3) for i in i3] for sl in initial_list]
def binyamin_numpy(initial_list):
return np.array(initial_list).repeat(3).reshape(len(initial_list), -1).tolist()
perfplot.show(
setup=lambda n: [shuffle([i for i in range(n)]) for j in range(n)],
n_range=[2**k for k in range(12)],
kernels=[
cdjb,aurora_sorted, aurora_list_comp, kederrac, alain_chain, alain_reduce, alain_zip, binyamin_numpy
],
xlabel='len(x)',
)
numpy 它,和 1 行代码:
arr=np.array(initial_list)
arr.repeat(3).reshape(3,-1)
输出:
Out[44]:
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[4, 4, 4, 5, 5, 5, 6, 6, 6],
[7, 7, 7, 8, 8, 8, 9, 9, 9]])
这是一个使用 2 for 循环的简单示例:
for l in initial_list:
for j in range(0, 3*len(l), 3):
l[j: j + 1] = [l[j]] * 3
我一直在针对@CDJB 解决方案进行测试(带排序):
from random import choice
def test1():
initial_list = [[choice(range(1000)) for _ in range(1000)] for _ in range(100)]
def my_func(initial_list):
for l in initial_list:
for j in range(0, 3*len(l), 3):
l[j: j + 1] = [l[j]] * 3
return initial_list
my_func(initial_list)
def test2():
initial_list = [[choice(range(1000)) for _ in range(1000)] for _ in range(100)]
[sorted(x*3, key=x.index) for x in initial_list]
结果如下:
%timeit test2()
1.55 s ± 5.12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
和:
%timeit test1()
165 ms ± 542 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
这个简单的解决方案快 9 倍,当然取决于您的数据
您可以使用 zip 和 chain(来自 itertools)来做到这一点:
from itertools import chain
aList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aList3 = [ list(chain(*(i3 for i3 in zip(*[sl]*3)))) for sl in aList ]
或者使用 functools 中的 reduce(结果证明在较大的列表上要慢得多):
from functools import reduce
aList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aList3 = [ list(reduce(lambda a,e:a+[e]*3,sl,[]))for sl in aList ]
或使用嵌套理解进行压缩(比链式压缩快一点):
aList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
aList3 = [[i for i3 in zip(*[sl]*3) for i in i3] for sl in initial_list]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.