Python(列表理解):为每个项目返回两个(或更多)项目

Has*_*ush 80 python list-comprehension

是否可以为列表理解中的每个项目返回2个(或更多)项目?

我想要的(例子):

[f(x), g(x) for x in range(n)]
Run Code Online (Sandbox Code Playgroud)

应该回来 [f(0), g(0), f(1), g(1), ..., f(n-1), g(n-1)]

所以,要替换这段代码:

result = list()
for x in range(n):
    result.add(f(x))
    result.add(g(x))
Run Code Online (Sandbox Code Playgroud)

nin*_*cko 93

双列表理解:

[f(x) for x in range(5) for f in (f1,f2)]
Run Code Online (Sandbox Code Playgroud)

演示:

>>> f1 = lambda x: x
>>> f2 = lambda x: 10*x

>>> [f(x) for x in range(5) for f in (f1,f2)]
[0, 0, 1, 10, 2, 20, 3, 30, 4, 40]
Run Code Online (Sandbox Code Playgroud)

  • 这很好,因为它表明双列表comps并不那么可怕:它们只是嵌套用于循环写入*就像for循环*一样.`for x in range(5):for f in(f1,f2):newlist.append(f(x))`.我曾经发现它们有点混乱,因为我一直试图颠倒顺序. (5认同)
  • 这应该是公认的答案,谢谢,太棒了! (2认同)

jam*_*lak 49

>>> from itertools import chain
>>> f = lambda x: x + 2
>>> g = lambda x: x ** 2
>>> list(chain.from_iterable((f(x), g(x)) for x in range(3)))
[2, 0, 3, 1, 4, 4]
Run Code Online (Sandbox Code Playgroud)

时序:

from timeit import timeit

f = lambda x: x + 2
g = lambda x: x ** 2

def fg(x):
    yield f(x)
    yield g(x)

print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in range(3)))',
             setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2')

print timeit(stmt='list(chain.from_iterable(fg(x) for x in range(3)))',
             setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2')

print timeit(stmt='[func(x) for x in range(3) for func in (f, g)]',
             setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2')


print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in xrange(10**6)))',
             setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)

print timeit(stmt='list(chain.from_iterable(fg(x) for x in xrange(10**6)))',
             setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)

print timeit(stmt='[func(x) for x in xrange(10**6) for func in (f, g)]',
             setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2',
             number=20)
Run Code Online (Sandbox Code Playgroud)

2.69210777094

3.13900787874

1.62461071932

25.5944058287

29.2623711793

25.7211849286

  • 这段代码创建了不必要的元组`(f(x),g(x))`.可以更好地写成:`def fg(x):yield x + 2; 产量x**2; list(chain.from_iterable(fg(x)for x in range(3)))`. (4认同)
  • 消失的第三个答案看起来像这样:`[y表示范围中的x(y)(y(f(x),g(x))]但是这可能更慢.@jamylak如果你愿意,你也可以测试一下. (3认同)

nin*_*cko 11

sum( ([f(x),g(x)] for x in range(n)), [] )
Run Code Online (Sandbox Code Playgroud)

这相当于 [f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...

您还可以将其视为:

def flatten(list):
    ...

flatten( [f(x),g(x)] for x in ... )
Run Code Online (Sandbox Code Playgroud)

注意:正确的方法是使用itertools.chain.from_iterable或双列表理解.(它不需要在每个+上重新创建列表,因此具有O(N)性能而不是O(N ^ 2)性能.)sum(..., [])当我想要一个快速的单行或我匆忙时,我仍然会使用,或当组合的术语数量有界时(例如<= 10).这就是我在这里提到它的原因.你也可以使用元组:( ((f(x),g(x)) for ...), ()或者每个khachik的评论,有一个产生两元组的生成器fg(x)).


Rai*_*rim 5

我知道 OP 正在寻找列表理解解决方案,但我想提供一种使用list.extend().

\n
f = lambda x: x\ng = lambda x: 10*x\n\nresult = []\nextend = result.extend\nfor x in range(5):\n    extend((f(x),g(x)))\n
Run Code Online (Sandbox Code Playgroud)\n

这比使用双重列表理解要快一些。

\n
f = lambda x: x\ng = lambda x: 10*x\n\nresult = []\nextend = result.extend\nfor x in range(5):\n    extend((f(x),g(x)))\n
Run Code Online (Sandbox Code Playgroud)\n

Python版本:3.8.0

\n