能否在列表推导式中为每个项返回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))
能否在列表推导式中为每个项返回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))
双重列表推导:
[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]
for x in range(5): for f in (f1, f2): newlist.append(f(x))
。我曾经觉得它们有点令人困惑,因为我一直试图颠倒顺序。 - DSM>>> 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
(f(x), g(x))
。可以改写成以下方式:def fg(x): yield x + 2; yield x ** 2; list(chain.from_iterable(fg(x) for x in range(3)))
。 - khachikchain.from_iterable((func(x) for func in funcs) for x in range(n)))
来进行泛化,这将消除khachik的抱怨。(虽然从某种意义上说,我们的过程本质上是相同的,只是我们对内部生成器的定义略有不同。) - JAB[]
的性能表现。 - ninjageckodef fg(x): yield f(x); yield g(x);
。 - JAB[y for x in range(n) for y in (f(x), g(x))]
。但这种方法可能比较慢。@jamylak 如果你愿意的话,也可以测试一下。 - Hashmushsum( ([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) 的性能。当我需要快速的一行代码或者时间紧迫,或者要结合的项数有界时(例如小于等于10),我仍然会使用 sum(..., [])
。这就是为什么我在这里提到它,并带有该警告。你还可以使用元组:((f(x),g(x)) for ...), ()
(或根据 khachik 的评论,使用生成器 fg(x) 生成两个元素的元组)。
[f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...
。 - ninjageckosum()
函数对于列表的使用是一种反模式,这是由于其灾难性能以及正确解决方案更为简洁所导致的。 - Sven Marnach我知道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
这个 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]
在合理的情况下,您应该优先使用itertools.product()
而不是在列表推导式中使用两个for
子句。一些风格指南,例如Google Python Style Guide禁止在列表推导式中使用多个for
子句。虽然您可能正在使用一个没有明确禁止这种做法的风格指南,但您仍然可以通过执行以下操作使推导更加简洁:
from itertools import product
result = [y(x) for y, x in product(range(n), (f, g))]
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)']
for
的实现:result = []
for n in some_data:
result += some_operation()
## etc.
例如,对于意图在列表或类似数据结构上产生副作用的for循环,可以使用累加器模式。
可以重构为声明性的map/reduce/filter
实现。
天啊!为什么要用那么多Lambda、Flatten、Zip和Sum?这不是最简单易读的方法吗:
>>> [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)
,或其他任何表达式。)