리스트 이해의 이중 반복


226

파이썬에서는 목록 이해에 여러 반복자를 가질 수 있습니다.

[(x,y) for x in a for y in b]

일부 적합한 서열 a 및 b. 파이썬의 목록 이해의 중첩 루프 의미를 알고 있습니다.

내 질문은 : 이해의 한 반복자가 다른 반복자를 참조 할 수 있습니까? 다른 말로하면 다음과 같습니다.

[x for x in a for a in b]

외부 루프의 현재 값은 내부의 반복자입니까?

예를 들어 중첩 목록이있는 경우 :

a=[[1,2],[3,4]]

이 결과를 달성하기 위해 목록 이해 표현은 무엇입니까?

[1,2,3,4]

?? (이것이 내가 알고 싶은 것이기 때문에 이해력 답변 만 나열하십시오).

답변:


178

자신의 제안으로 질문에 대답하려면 :

>>> [x for b in a for x in b] # Works fine

목록 이해 답변을 요청하는 동안 훌륭한 itertools.chain ()도 지적하겠습니다.

>>> from itertools import chain
>>> list(chain.from_iterable(a))
>>> list(chain(*a)) # If you're using python < 2.6

11
[x for b in a for x in b]이것은 항상 파이썬에 관한 것입니다. 이 구문은 너무 거꾸로 있습니다. 의 일반적인 형식은 x for x in y항상 for 바로 뒤에 변수가 있으며 for 왼쪽의 표현식으로 전달됩니다. 이중 이해를하자마자 가장 최근에 반복 된 변수는 갑자기 너무 멀다. 어색하고 자연스럽게 읽지 않습니다
Cruncher

170

a,b,x,y에게 큰 의미가 없기 때문에 이것이 다른 누군가를 돕기를 바랍니다 . 문장으로 가득 찬 텍스트가 있고 단어 배열을 원한다고 가정하십시오.

# Without list comprehension
list_of_words = []
for sentence in text:
    for word in sentence:
       list_of_words.append(word)
return list_of_words

나는 목록 이해력을 수평으로 늘리는 것으로 생각하고 싶다.

그것을 다음과 같이 나누십시오.

# List Comprehension 
[word for sentence in text for word in sentence]

예:

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> [word for sentence in text for word in sentence]
['Hi', 'Steve!', "What's", 'up?']

이것은 발전기에서도 작동합니다.

>>> text = (("Hi", "Steve!"), ("What's", "up?"))
>>> gen = (word for sentence in text for word in sentence)
>>> for word in gen: print(word)
Hi
Steve!
What's
up?

8
"컴퓨터 과학에는 두 가지 어려운 문제가있다 : 캐시 무효화와 이름 지정 문제."
-Phil

이것은 전체 문제를 덜 추상적으로 만들기 때문에 훌륭한 답변입니다! 감사합니다!
A. Blesius

나는 목록 이해에서 세 가지 추상화 수준으로 동일한 작업을 수행 할 수 있습니까? 텍스트의 챕터, 챕터의 문장 및 문장의 단어처럼?
캡틴 포가티

123

Gee, 나는 anwser를 발견했다고 생각한다. 나는 어떤 루프가 내부이고 어떤 루프가 외부인지에 대해 충분히 신경 쓰지 않고 있었다. 목록 이해력은 다음과 같아야합니다.

[x for b in a for x in b]

원하는 결과를 얻으려면 예, 현재 값 중 하나는 다음 루프의 반복자가 될 수 있습니다.


67
리스트 이해 구문은 파이썬의 빛나는 포인트 중 하나가 아닙니다.
Glenn Maynard

2
@Glenn 예, 단순한 표현 이상으로 쉽게 복잡해집니다.
ThomasH

1
으. 이것이 목록 이해에 "일반적인"사용인지 확실하지 않지만, 파이썬에서 체인이 너무 불쾌한 것은 매우 불행합니다.
Matt Joiner

14
각 'for'앞에 개행을 넣으면 매우 깨끗해 보입니다.
Nick Garvey

16
와우, 이것은 내 머리에 의미가있는 것과 완전히 반대입니다.
obskyr 2016 년

51

반복자의 순서는 직관적이지 않을 수 있습니다.

예를 들어 보자. [str(x) for i in range(3) for x in foo(i)]

그것을 분해하자 :

def foo(i):
    return i, i + 0.5

[str(x)
    for i in range(3)
        for x in foo(i)
]

# is same as
for i in range(3):
    for x in foo(i):
        yield str(x)

4
얼마나 눈을 뜨는가!
nehem

필자가 이해 한 이유는 "첫 번째 반복이 이해가 루프에 대해 중첩으로 작성된 경우 입력되는 최상위 반복"이기 때문입니다. 직관적이지 않은 이유는 OUTER 루프 (중첩 된 for 루프로 작성된 경우 최상위)가 괄호로 묶인 목록 / dict (이해 된 객체)의 INSIDE에 나타나기 때문입니다. 반대로, INNER 루프 (중첩 된 for 루프로 작성 될 때 가장 안쪽에 있음)는 정확하게 이해하는 가장 오른쪽의 루프이며, 이러한 방식으로 이해의 외부에 나타납니다.
Zach Siegel

초록 과 우리는 and 와 [(output in loop 2) (loop 1) (loop 2)]함께했습니다 . (loop 1) = for i in range(3)(loop 2) = for x in foo(i):(output in loop 2) = str(x)
Qaswed

20

ThomasH는 이미 좋은 답변을 추가했지만 어떻게되는지 보여주고 싶습니다.

>>> a = [[1, 2], [3, 4]]
>>> [x for x in b for b in a]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined

>>> [x for b in a for x in b]
[1, 2, 3, 4]
>>> [x for x in b for b in a]
[3, 3, 4, 4]

파이썬이 목록 이해를 왼쪽에서 오른쪽으로 구문 분석한다고 생각합니다. 즉, for발생 하는 첫 번째 루프가 먼저 실행됩니다.

이것의 두 번째 "문제" b는 목록 이해에서 "누설" 된다는 것입니다. 첫 번째 성공적인 목록 이해 후 b == [3, 4].


3
흥미로운 점. 나는 이것에 놀랐다 :x = 'hello'; [x for x in xrange(1,5)]; print x # x is now 4

2
이 누설은 파이썬 3에서 수정되었습니다 : stackoverflow.com/questions/4198906/...
데닐손 Sá 마이 아를

10

다차원 배열을 유지하려면 배열 괄호를 중첩해야합니다. 모든 요소에 하나가 추가되는 아래 예를 참조하십시오.

>>> a = [[1, 2], [3, 4]]

>>> [[col +1 for col in row] for row in a]
[[2, 3], [4, 5]]

>>> [col +1 for row in a for col in row]
[2, 3, 4, 5]

8

이 메모리 기술은 많은 도움이됩니다.

[ <RETURNED_VALUE> <OUTER_LOOP1> <INNER_LOOP2> <INNER_LOOP3> ... <OPTIONAL_IF> ]

그리고 지금 당신에 대해 생각할 수있는 R eturn + O 유일한로 터의 루프 R ight O RDER

위에서 알 수 있듯이 3 루프에서도 포괄적 인 목록의 순서는 쉽습니다.


c=[111, 222, 333]
b=[11, 22, 33]
a=[1, 2, 3]

print(
  [
    (i, j, k)                            # <RETURNED_VALUE> 
    for i in a for j in b for k in c     # in order: loop1, loop2, loop3
    if i < 2 and j < 20 and k < 200      # <OPTIONAL_IF>
  ]
)
[(1, 11, 111)]

위의 내용은 다음과 같습니다.

for i in a:                         # outer loop1 GOES SECOND
  for j in b:                       # inner loop2 GOES THIRD
    for k in c:                     # inner loop3 GOES FOURTH
      if i < 2 and j < 20 and k < 200:
        print((i, j, k))            # returned value GOES FIRST

하나의 중첩 된 목록 / 구조를 반복하는 경우 기술은 동일 a합니다.

a = [[1,2],[3,4]]
[i2    for i1 in a      for i2 in i1]
which return [1, 2, 3, 4]

서로 중첩 된 레벨

a = [[[1, 2], [3, 4]], [[5, 6], [7, 8, 9]], [[10]]]
[i3    for i1 in a      for i2 in i1     for i3 in i2]
which return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

등등


고맙지 만 설명하는 것은 실제로 관련된 반복자가 독립적 인 간단한 경우입니다. 실제로 예제에서 반복자 를 임의 순서로 사용할 수 있으며 동일한 결과 목록 (모듈로 순서)을 얻을 수 있습니다. 내가 더 관심이있는 경우는 하나의 반복자가 다음 반복기가 반복되는 중첩 된 목록입니다.
ThomasH

@ThomasH : 굵게 정의 된 루프의 순서는 정확히 당신의 필요를위한 것입니다. 맨 아래에는 데이터를 포함하는 예제와 추가 중첩 수준이있는 예제가 하나 더 추가되었습니다.
Sławomir Lenart

5

이해하기 쉽다고 생각합니다

[row[i] for row in a for i in range(len(a))]

result: [1, 2, 3, 4]

3

또한 현재 액세스되는 입력 목록의 구성원에 대해 그냥 같은 변수를 사용할 수 있습니다 이 구성원 내부의 요소. 그러나 이로 인해 이해하기 어려워 질 수도 있습니다.

input = [[1, 2], [3, 4]]
[x for x in input for x in x]

첫 번째 for x in input는 입력의 하나의 멤버 목록으로 이어지고, 파이썬은 두 번째 부분을 거치며 for x in x액세스하는 현재 요소가 x 값을 덮어 쓰는 동안 첫 번째 부분 x을 반환합니다.


1

이 flatten_nlevel 함수는 중첩 된 list1을 재귀 적으로 호출하여 한 레벨로 은밀합니다. 이것을 사용해보십시오

def flatten_nlevel(list1, flat_list):
    for sublist in list1:
        if isinstance(sublist, type(list)):        
            flatten_nlevel(sublist, flat_list)
        else:
            flat_list.append(sublist)

list1 = [1,[1,[2,3,[4,6]],4],5]

items = []
flatten_nlevel(list1,items)
print(items)

산출:

[1, 1, 2, 3, 4, 6, 4, 5]

1
좋아, 질문은 특히 목록 이해에 관한 것이었고, 목록 병합은 단지 예일뿐입니다. 그러나 일반 목록 플래트너는 재귀 적으로 호출해야한다고 가정합니다. 아마 더 비슷 flatten_nlevel(sublist, flat_list)할까요?!
ThomasH
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.