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

时间:2012-08-08 16:27:53

标签: python list-comprehension

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

我想要的(例子):

[f(x), g(x) for x in range(n)]

应该返回[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))

7 个答案:

答案 0 :(得分:86)

双重列表理解:

[f(x) for x in range(5) for f in (f1,f2)]

演示:

>>> 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]

答案 1 :(得分:44)

>>> 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]

时序:

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)
  

2.69210777094

     

3.13900787874

     

1.62461071932

     

25.5944058287

     

29.2623711793

     

25.7211849286

答案 2 :(得分:10)

sum( ([f(x),g(x)] for x in range(n)), [] )

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

您还可以将其视为:

def flatten(list):
    ...

flatten( [f(x),g(x)] for x in ... )

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

答案 3 :(得分:2)

这个lambda函数将两个列表分成一个列表:

zipped = lambda L1, L2: [L[i] 
                         for i in range(min(len(L1), len(L2))) 
                         for L in (L1, L2)]

示例:

>>> f = [x for x in range(5)]
>>> g = [x*10 for x in range(5)]
>>> zipped(f, g)
[0, 0, 1, 10, 2, 20, 3, 30, 4, 40]

答案 4 :(得分:2)

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

f = lambda x: x
g = lambda x: 10*x

result = []
extend = result.extend
for x in range(5):
    extend((f(x),g(x)))

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

nums = range(100000)

def double_comprehension():
    return [func(x) for x in nums for func in (f,g)]

def list_extend():
    result = []
    extend = result.extend
    for x in nums:
        extend((f(x),g(x)))
    return result

%timeit -n100 double_comprehension()
23.4 ms ± 67 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit -n100 list_extend()
20.5 ms ± 213 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Python版本:3.8.0

答案 5 :(得分:0)

使用reduce的解决方案:

from functools import reduce

f    = lambda x: f"f({x})" ## Just for example
g    = lambda x: f"g({x})"
data = [1, 2, 3]

reduce(lambda acc, x: acc + [f(x), g(x)], data, [])
# => ['f(1)', 'g(1)', 'f(2)', 'g(2)', 'f(3)', 'g(3)']

虽然不是列表理解,但这是解决问题的一种实用方法。列表理解本质上是map遍历数据的另一种方法,但是在这种情况下,输入与输出之间不是一对一的映射,reduce允许在输出方式上留出一些空间可以生成。

通常,以下形式的任何for实现:

result = []
for n in some_data:
  result += some_operation()
  ## etc.

(即用于旨在对列表或类似数据结构产生副作用的循环)

可以重构为声明性的map/reduce/filter实现。

答案 6 :(得分:-2)

天哪,悲痛!为什么所有这些 lambdas、flattens、zips 和 sums?这不是最简单和最易读的:

>>> [v
...  for x in range(5)
...      for v in (2 * x,
...                2 * x + 1)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

(将最后两个表达式替换为 f(x)g(x) 或其他。)