【问题标题】:Possible to return two lists from a list comprehension?可以从列表理解中返回两个列表吗?
【发布时间】:2012-05-07 08:59:33
【问题描述】:

是否可以从列表推导中返回两个列表?好吧,这显然行不通,但是类似于:

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

所以rrtt 都是列表,结果分别来自i*10i*12。 非常感谢

【问题讨论】:

    标签: python list-comprehension


    【解决方案1】:
    >>> rr,tt = zip(*[(i*10, i*12) for i in xrange(4)])
    >>> rr
    (0, 10, 20, 30)
    >>> tt
    (0, 12, 24, 36)
    

    【讨论】:

    • 只运行两个单独的列表推导更简单,而且可能更快。
    • 我在上面发布的只是一个简单的例子。实际上,我正在使用 for 循环来过滤一些条目,然后调用一个函数,结果非常慢,因为我为 item 调用了函数 item。所以我想我最好将两个列表传递给函数以加快速度。好吧,我要做一些测试...谢谢伙计!
    • 您必须给列表理解一个参数(在这种情况下,它是一个必须解压缩的元组。要完成此操作,您必须使用 * 运算符。看看 [这里] :(docs.python.org/library/functions.html#zip)
    • @thavan * 将列表推导解包为 zip 的参数。您可以查看“列表解包”以获取更多信息。
    • @KarlKnechtel:渐近地说,任何时候一个循环都会胜过两个循环。
    【解决方案2】:

    创建两个推导式列表更好(至少对于长列表)。请注意,最佳投票答案较慢可能比传统的 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 循环来过滤一些条目,然后调用一个函数,结果非常慢,因为我为 item 调用了函数 item”。我将其视为一个带有return x, y 的函数,希望将所有x 保留在一个列表中,而将所有y 保留在另一个列表中。在这种情况下进行两次推导会不必要地加倍时间复杂度,因为您在第一次推导中丢弃了 y(计算成本很高)......只是为了再次重新计算它们并这次丢弃 x。在这种情况下,我认为zip(*) 更好。
    • @Reedinationer,只要内部计算完全相同,理解列表仍然更好。我做了一些测试,看到结果我很惊讶。然而,很明显:你在做什么并不重要(因为它在所有情况下都是一样的),重要的是你循环的速度。也就是说,如果您可以利用传统循环(特别是使用时间变量),那么您可能会更好地使用它(或 @987654329 @ 和 zip `)。但是,差异可以归因于内部计算(代码)。
    • 我认为您的观点仍然非常有效,很难从那句话中推断出 OP 的确切含义。所以,我扩展了我的答案。
    【解决方案3】:

    如果元素是列表,列表推导可能会返回多个列表。 比如:

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

    zip 函数的诀窍可以完成这项工作,但如果您只是通过循环将结果收集到列表中,实际上会更加简单和易读。

    【讨论】:

    • 呃,这和问题有什么关系?这仅适用于range(2),因为只有这样你才能得到两个列表。然后是空列表。
    • 问题是:'是否可以从列表理解中返回两个列表?'。我回答这是可能的,但我认为最好使用循环进行迭代并将结果收集到两个单独的列表中。
    猜你喜欢
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多