Подтвердить что ты не робот

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))
4b9b3361

Ответ 1

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

Двойное распознавание списка:

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

Ответ 3

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 ...), () (или за комментарий к хачику, имеющий генератор fg (x), который дает двухкортеж).

Ответ 4

Эта лямбда-функция застегивает два списка в один:

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]