목록 이해력 : 각 항목에 대해 두 개 이상의 항목 반환


89

목록 이해의 각 항목에 대해 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))

3
호기심에 왜 이러고 싶어? 이런 식으로 시도하지 않고 최종 목표를 달성하는 더 좋은 방법이있을 수 있습니다.
murgatroid99

3
주로 함수형 프로그래밍을 좋아하기 때문입니다. pyglet.graphics.draw 함수와 함께 사용할 화면 좌표의 튜플에 좌표 목록을 매핑하고 싶습니다.
Hashmush

답변:


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


4
이 코드는 불필요한 튜플을 생성 (f(x), g(x))합니다. 다음과 같이 더 잘 작성할 수 있습니다 def fg(x): yield x + 2; yield x ** 2; list(chain.from_iterable(fg(x) for x in range(3)))..
khachik

1
으로 일반화 할 수도 있습니다 chain.from_iterable((func(x) for func in funcs) for x in range(n))). 우연히 khachik의 불만을 제거합니다. (어떤 의미에서 나와 그의 프로세스는 본질적으로 동일합니다. 단순히 내부 생성기를 다르게 정의합니다.)
JAB

이것은 sum(..., [])모든 +에 대한 목록을 다시 만들 필요가 없기 때문에 내 대답 보다 낫습니다 (따라서 O (N ^ 2) 성능이 아닌 O (N) 성능이 있습니다). 나는 아직도 사용합니다 sum(..., [])나는 빠른 한 - 라이너를 원하거나 내가 서둘러 해요, 또는 결합 된 용어의 수는 경계 할 때 (예를 들어 <= 10) 때.
ninjagecko

@khachik 나는 이것이 더 빠를 것이라고 생각하지만 지금은 두 가지 방법을 모두 시간을 정할 것입니다. 튜플은 파이썬에서 매우 빠르게 생성됩니다.
jamylak 2012-08-08

3
사라진 세 번째 대답은 다음과 같았습니다. [y for x in range(n) for y in (f(x), g(x))]그러나 이것은 아마도 더 느릴 것입니다. @jamylak 원한다면 이것도 테스트 할 수 있습니다.
Hashmush

118

이중 목록 이해 :

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

10
이것은 이중 목록 구성 요소가 그렇게 무섭지 않다는 것을 보여주기 때문에 좋습니다 : 그들은 단순히 for 루프 처럼 작성된 중첩 된 for 루프입니다 . for x in range(5): for f in (f1, f2): newlist.append(f(x)). 나는 계속해서 순서를 뒤집으려고 노력했기 때문에 조금 혼란스러워했습니다.
DSM

1
이것은 받아 들여진 대답이어야합니다. 감사합니다, 놀랍습니다!
Wingjam

@DSM은 영원히 혼란 스러울 것입니다.)
Winand

11
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 ^ 2) 성능보다 O (N) 성능이 있습니다.) sum(..., [])빠른 한 줄짜리를 원하거나 서둘러야 할 때 계속 사용할 것입니다. , 또는 결합되는 용어의 수가 제한된 경우 (예 : <= 10). 그렇기 때문에이 경고와 함께 여기서 언급합니다. 튜플을 사용할 수도 있습니다 ((f(x),g(x)) for ...), ().


@ArashThr :하고 있습니다 [f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...
ninjagecko

정확히 무엇을하고 있는지 설명 할 수 있습니까?
Rsh

참고 : 여기에는 O (N ^ 2) 런타임이 있으므로 방대한 목록에서 느려질 수 있습니다.
jamylak 2012-08-08

1
@jamylak : 예, 댓글에서도 답변에 이것을 언급했습니다. =)
ninjagecko

나는 sum()이런 식으로 남용 하는 것을 반 패턴이라고 생각하며 어떤 상황에서든 그것을 사용할 이유가 없다고 생각합니다. 다른 답변의 코드는 타이핑이 적기 때문에 "빠른 한 줄짜리를 원하거나 서둘러 할 때"라는 변명조차도 실제로 그것을 자르지 않습니다.
Sven Marnach

2

이 람다 함수는 두 개의 목록을 하나의 목록으로 압축합니다.

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]

2

OP가 목록 이해 솔루션을 찾고 있다는 것을 알고 있지만 .NET을 사용하는 대안을 제공하고 싶습니다 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


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.

(즉, 목록 또는 유사한 데이터 구조에 부작용을 일으키기위한 for 루프)

선언적 map/reduce/filter구현 으로 리팩토링 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.