从列表推导式中返回两个列表是否可行?

60

能否在列表推导式中返回两个列表?显然下面的写法不起作用,但是是否有类似以下的解决方案:

rr, tt = [i*10, i*12 for i in xrange(4)]

所以rrtt都是列表,分别包含i*10i*12的结果。

感谢您!

3个回答

95
>>> rr,tt = zip(*[(i*10, i*12) for i in xrange(4)])
>>> rr
(0, 10, 20, 30)
>>> tt
(0, 12, 24, 36)

7
单独使用两个列表推导更简单,可能也更快。 - Karl Knechtel
1
我上面发布的只是一个简单的例子。实际上,我正在使用for循环来过滤一些条目,然后调用一个函数,结果发现这个函数非常慢,因为我逐个调用了它的每个项目。因此,我想最好传递两个列表给该函数以加快速度。好的,我打算进行一些测试……谢谢你,伙计! - LarsVegas
1
你必须给列表推导式一个参数(在这种情况下是一个需要解压的元组)。为了实现这一点,你必须使用 * 运算符。请参考这里 - LarsVegas
2
@thavan * 将列表推导式解包为 zip 的参数。您可以查找“列表解包”以获取更多信息。 - jamylak
1
这不会返回两个列表,type(rr)type(tt)tuple。OP 要求两个列表。 - Confounded
显示剩余4条评论

29

创建两个 comprehension 列表更好(至少对于长列表而言)。需要注意的是,即使 最佳答案的投票次数最多,它的速度可能还不如传统的 for 循环。 列表推导式更快且更清晰

python -m timeit -n 100 -s 'rr=[];tt = [];' 'for i in range(500000): rr.append(i*10);tt.append(i*12)' 
10 loops, best of 3: 123 msec per loop

> python -m timeit -n 100 'rr,tt = zip(*[(i*10, i*12) for i in range(500000)])' 
10 loops, best of 3: 170 msec per loop

> python -m timeit -n 100 'rr = [i*10 for i in range(500000)]; tt = [i*10 for i in range(500000)]' 
10 loops, best of 3: 68.5 msec per loop

希望能看到列表推导式支持一次创建多个列表。

然而,

如果你可以利用传统的循环(确切地说,是中间计算), 那么使用循环(或者使用 yielditerator/generator)可能会更好。下面是一个例子:

$ python3 -m timeit -n 100 -s 'rr=[];tt=[];' "for i in (range(1000) for x in range(10000)): tmp = list(i); rr.append(min(tmp));tt.append(max(tmp))" 
100 loops, best of 3: 314 msec per loop

$ python3 -m timeit -n 100 "rr=[min(list(i)) for i in (range(1000) for x in range(10000))];tt=[max(list(i)) for i in (range(1000) for x in range(10000))]"
100 loops, best of 3: 413 msec per loop
当然,在这些情况下进行比较是不公平的;在这个例子中,代码和计算并不相等,因为在传统循环中会存储一个临时结果(请参见 tmp 变量)。因此,列表推导式执行了更多的内部操作(它计算 tmp 变量两次!),但只慢了25%。

但 OP 在评论中说:“我正在使用 for 循环来筛选一些条目,然后调用一个函数,结果发现这个函数非常慢,因为我对每一个项目都调用了函数。”我理解为一个带有 return x, y 的函数想要将所有的 x 放在一个列表中,所有的 y 放在另一个列表中。在这种情况下做两个推导式会不必要地增加时间复杂度,因为你在第一个推导式中扔掉了昂贵的 y 值...只是为了再次计算它们并且这次扔掉 x 值。在这种情况下我认为 zip(*) 更好。 - Reedinationer
@Reedinationer,只要内部计算完全相同,理解列表仍然更好。我做了一些测试,看到了结果,感到惊讶。然而,很快就变得明显:无论你在做什么(因为所有情况都是相同的),重要的是你循环的速度有多快。也就是说,如果你能利用传统循环(特别是使用临时变量)的任何优势,那么你可能会更好地使用它(或者使用iterator/generatorzip)。但是,差异可以归因于内部计算(代码)。 - toto_tico
我认为你的观点仍然非常有价值,从那个句子中很难推断出OP确切的意思。因此,我扩展了我的答案。 - toto_tico

-3

如果列表元素是列表,那么列表推导式可以返回多个列表。

例如:

>>> x, y = [[] for x in range(2)]
>>> x
[]
>>> y
[]
>>>

zip函数的技巧可以完成任务,但如果您只是使用循环将结果收集到列表中,实际上会更简单和易读。


8
这与问题有什么关系?这只适用于range(2),因为只有这样你才会得到正好两个空列表。 - Tim Pietzcker
问题是:“能否从列表推导式中返回两个列表?” 我回答说是可能的,但我认为最好使用循环迭代并将结果收集到两个单独的列表中。 - Mariy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接