2016-09-12 3 views
2

정확하게이 함수가 사용하고있는 프로그래밍 마술로 인해이 함수가하는 일을 정확히 이해하는 데 문제가 있습니까?itertools.groupby 함수가 일관성이없는 것처럼 보입니다

iterator와 쌍을 이루는 키 목록 (문자열의 고유 한 문자)을 반환하는 것처럼 보입니다.이 문자열은 원래 문자열의 각 문자 수 목록을 참조하지만 때로는 이렇게 보입니다. 그렇지 않아. 예를 들어

: 인쇄

import itertools 

x = list(itertools.groupby("AAABBB")) 
print x 

: 이것은 올바른 것 같다

[('A', <itertools._grouper object at 0x101a0b050), 
('B', <itertools._grouper object at 0x101a0b090)] 

, 우리는 반복자와 짝을 우리의 고유 키가 있습니다.

print list(x[0][1]) 

내가 얻을 :

[] 

을 내가

for k, g in x: 
    print k + ' - ' + g 

을 실행할 때 내가 얻을 :하지만 실행할 때

B - <itertools._grouper object at 0x1007eedd5> 

그것은 첫 번째 요소를 무시합니다. 내가 할

[list(g) for k, g in itertools.groupby("AAABBB")] 

:이 난 그냥 문법을 약간 변경하는 경우 때문에, 반 직관적 보인다

[["A", "A", "A"], ["B", "B", "B"]] 

맞다, 나는이 기능은 일을해야 생각으로 정렬합니다. 나는 다시 한 번 구문을 조금 변경하면

그러나 :

[[], ['B']] 

이 두 지능형리스트가 직접 동일해야하지만 서로 다른 결과를 반환 :

[list(thing) for thing in [g for k, g in itertools.groupby(string)]] 

을 내가 다시 얻을.

무슨 일입니까? 통찰력은 대단히 감사하겠습니다.

+1

최상위 레벨 반복기를 진행하자마자'group' 반복기가 유효하지 않게됩니다. – ShadowRanger

답변

6

워드 프로세서는 이미 설명 :-) 도움이되기를 바랍니다 :

반환 된 그룹은 GROUPBY와 반복자를 기본()을 공유하는 반복자 자체입니다. 소스가 공유되기 때문에 groupby() 객체가 고급 상태 일 때 이전 그룹은 더 이상 볼 수 없습니다. 데이터가 나중에 필요할 경우에 따라서,이 목록

로 저장해야합니다 귀하의 작동 있도록

[list(g) for k, g in itertools.groupby("AAABBB")] 

groupby() 진보 이전 사용 각 그룹을합니다.

당신의
[list(thing) for thing in [g for k, g in itertools.groupby(string)]] 

모든 그룹이 생성 된 후 때까지 그룹을 사용하지 않습니다. 전혀 같은 것은 아니며, 인용 된 문서가 설명 된 이유 때문입니다.

4

예상되는 대답을 얻으려면 반환 된 반복기를 목록으로 변환하십시오.

Groupby은 입력 반복자를 느리게 사용합니다 (즉, 필요에 따라 데이터를 읽음). 새 그룹을 찾으려면 다음 같지 않은 요소 (다음 그룹의 첫 번째 구성원)까지 읽어야합니다. 하위 그룹 반복자 목록에 있으면 현재 그룹의 끝으로 입력이 전진합니다.

일반적으로 다음 그룹으로 이동하면 이전에 반환 된 하위 그룹 반복기에는 데이터가 없으므로 빈 것으로 표시됩니다. 따라서 하위 그룹 반복자에서 데이터가 필요한 경우 목록앞에이 표시되어야 다음 그룹으로 넘어갑니다.

이 동작의 이유는 반복자가 한 번에 하나의 데이터를보고 메모리에서 불필요한 것을 유지하지 않기 때문입니다.

가 여기에 모든 작업을 볼 수 있도록 몇 가지 코드입니다 :

from itertools import groupby 

def supply(): 
    'Make the lazy input visible' 
    for c in 'aaaaabbbcdddddddeeee': 
     print('supplying %r' % c) 
     yield c 

print("\nCase where we don't consume the sub-iterator") 
for k, g in groupby(supply()): 
    print('Got group for %r' % k) 

print("\nCase where we do consume the sub-iterator before advancing") 
for k, g in groupby(supply()): 
    print('Got group for %r' % k) 
    print(list(g)) 

"미친 당신을 운전"의 예에서, 목록 작업은 (외부 지능형리스트에서) 너무 늦게 적용되고있다. 이 솔루션은 내부 이해에 목록 단계를 이동하는 것입니다 :

>>> import itertools 
>>> [list(g) for k, g in itertools.groupby('aaaaabbbb')] 
>>> [['a', 'a', 'a', 'a', 'a'], ['b', 'b', 'b', 'b']] 

당신이 정말로 다음 grouped = [list(g) for k, g in itertools.groupby(data)] 갈 완벽하게 합리적인 방법입니다 실행 메모리를 절약 걱정하지 않는 경우

. 그런 다음 언제든지 원하는 하위 목록에서 데이터를 조회 할 수 있으며 반복기가 소비되는시기에 대한 규칙의 적용을받지 않아도됩니다. 일반적으로 목록의 목록은 반복자보다 쉽게 ​​작업 할 수 있습니다. 이것이 당신의 listcomps가 동일하지 왜

+0

그 것이 쉽다면 좋겠지 만 선행 적으로 목록으로 변환하면 개별 요소의 하위 반복자가 부정확 해지는 이상한 일이 발생합니다. 위의 'A'에 대한 반복자는 빈 목록으로 변환 된 것이고 다른 곳에서는 건너 뛴 것입니다. – bgenchel

+1

'groupby'에 대한 문서를 읽으십시오. https://docs.python.org/2/library/itertools.html#itertools.groupby 주목할만한 것은 : "반환 된 그룹 자체는 기본 iterable을 공유하는 반복자입니다. groupby() 객체가 공유 될 때 소스가 공유되기 때문에 이전 그룹을 더 이상 볼 수 없습니다. " 선제 적으로 목록으로 변환하면 바깥 쪽 반복자가 완전히 앞으로 나아가고 내부 반복자가 차례대로 진행됩니다. –

+0

@bgenchel :'[list in thing for ...]'줄에 대해 묻는다면, 반복되는리스트를 보아라 : [g for k, groupby의 g ('AAABBB')]'. 그것은 두 개의 반복자 ('_grouper' 생성자)를 포함합니다 - 하나는 비어 있고 하나는 거의 비어 있습니다. "...와 대략 같다"는 소스 코드는 각각''self.currvalue''를 산출 할 준비가되어 있습니다 만, 마지막''grouper''만이''self.currkey == tgtkey'' 조건을 만족시킵니다 while 루프의 그래서 마지막'_grouper'는 정확히 하나의 값을 산출하고 ('[ 'B']'리스트를 생성합니다), 그리고 나서'Stopiteration'을 만나게됩니다. –