同时生成两个列表

2 投票
3 回答
2816 浏览
提问于 2025-04-15 13:59

背景

这个算法处理的是金融分析的数据。有多个大小相同的列表,这些列表会被过滤成其他列表以便进行分析。我在不同的并行列表上做同样的过滤。我可以把a1、b1、c2放在一个元组里,然后放到一个列表中,但这样的话,分析时就得反过来处理这些元组(比如对一个列表进行回归分析,计算beta值等等)。

我想做的事情

我想根据第三个列表生成两个不同的列表:

>>> a = list(range(10))
>>> b = list(range(10,20))
>>> c = list(i & 1 for i in range(10))
>>>
>>> aprime = [a1 for a1, c1 in zip(a,c) if c1 == 0]
>>> bprime = [b1 for b1, c1 in zip(b,c) if c1 == 0]
>>> aprime
[0, 2, 4, 6, 8]
>>> bprime
[10, 12, 14, 16, 18]

看起来应该有一种更符合Python风格的方法,或者用函数式编程和itertools库来创建这两个列表,并且只遍历这三个列表一次。类似于:

aprime, bprime = [a1, b1 for a1, b1, c1 in zip(a,b,c) if c1 == 0]

但当然,这样会产生语法错误。

问题

有没有一种符合Python风格的方法?

微优化对决

那种看起来不太好但极其符合Python风格的一行代码在流行的timeit测试中,胜过了“只用for循环”的解决方案和我最初的代码:

>>> import timeit
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\treturn zip(*[(a1,b1) for a1,b1,c1 in zip(a,b,c) if c1==0])\n")
26.977873025761482
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\taprime, bprime = [], [];\n\tfor a1, b1, c1 in zip(a, b, c):\n\t\tif c1 == 0:\n\t\t\taprime.append(a1);  bprime.append(b1);\n\treturn aprime, bprime\n")
32.232914169258947
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\treturn [a1 for a1, c1 in zip(a,c) if c1 == 0], [b1 for b1, c1 in zip(b,c) if c1 == 0]\n")
32.37302275847901

3 个回答

0

用列表推导式一次性创建多个列表是不可能的。如果你只想遍历一次,那就得用其他方法,比如用循环。

你可以用列表推导式来创建一个包含元组的列表,第一个元素属于一个列表,第二个元素属于另一个列表。但是如果你想要它们作为独立的列表,那你还是得用其他方法来分开它们。

4

只需要用一个 for 循环就可以了:

aprime = []
bprime = []
for a1, b1, c1 in zip(a, b, c):
    if c1 == 0:
        aprime.append(a1) 
        bprime.append(b1) 
5

这段代码可能会被评为最丑的代码,但它只用一行就能完成任务:

aprime, bprime = zip(*[(a1,b1) for a1,b1,c1 in zip(a,b,c) if c1==0])

撰写回答