파이썬에서 목록을 페어 (현재, 다음)로 반복하십시오.


131

파이썬에서 "현재"요소와 "다음"요소를보고 목록을 반복해야하는 경우가 있습니다. 지금까지 다음과 같은 코드로 수행했습니다.

for current, next in zip(the_list, the_list[1:]):
    # Do something

이것은 효과가 있고 내가 기대하는 것을 수행하지만 같은 일을하는 관용적이거나 효율적인 방법이 있습니까?


이 질문에 대한 MizardX 답변을 확인하십시오 . 그러나 나는이 솔루션이 당신보다 관용적이라고 생각하지 않습니다.
Fábio Diniz


39
다른 사람이 언급하지 않았기 때문에 나는 그 사람이 될 것이며, next이 방법 을 사용 하면 내장 기능을 숨 깁니다.
senderle

@senderle 아마도 파이썬 2 일 것입니다.
Quintec

2
@ thecoder16 : next은 Python 2의 내장 함수이기도합니다.
zondo

답변:


131

itertools 모듈 문서 의 관련 예제는 다음과 같습니다 .

import itertools
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = itertools.tee(iterable)
    next(b, None)
    return zip(a, b)   

Python 2의 경우 다음 itertools.izip대신에 필요 합니다 zip.

import itertools
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = itertools.tee(iterable)
    next(b, None)
    return itertools.izip(a, b)

작동 방식 :

첫째, 두 개의 평행 반복기, ab(생성되는 tee()통화), 반복 가능한 원래의 첫 번째 요소를 모두 가리키는. 두 번째 반복자 b는 1 단계 앞으로 이동합니다 ( next(b, None)). 이 시점 a에서 s0을 b가리키고 s1을 가리 킵니다. 모두 ab독립적으로 원래의 반복자를 통과 할 수 - izip 기능은 두 반복자를 받아 같은 속도로 두 반복자를 발전 반환 된 요소의 쌍을, 수 있습니다.

한 가지주의 사항 :이 tee()함수는 서로 독립적으로 진행할 수있는 두 개의 반복자를 생성하지만 비용이 발생합니다. 반복자 중 하나가 다른 반복자보다 tee() 앞당겨진 경우, 두 번째 반복자가 너무 많이 소모 될 때까지 소비 된 요소를 메모리에 유지해야합니다 (원래 반복자를 '되감기'할 수 없음). 하나의 반복자가 다른 반복자보다 한 걸음 앞서 있기 때문에 중요하지 않지만 일반적 으로이 방법으로 많은 메모리를 사용하는 것은 쉽습니다.

그리고 이후 tee()취할 수있는 n매개 변수를,이 또한 두 개 이상의 병렬 반복자에 사용할 수 있습니다 :

def threes(iterator):
    "s -> (s0,s1,s2), (s1,s2,s3), (s2, s3,4), ..."
    a, b, c = itertools.tee(iterator, 3)
    next(b, None)
    next(c, None)
    next(c, None)
    return zip(a, b, c)

4
예제 코드는 훌륭하지만 ... 왜 작동하는지 조금 설명해 주시겠습니까? "tee ()"와 "next ()"가 무엇을하고 있는지 말하십시오.
존 멀더

@ 존 멀더 : 짧은 요약했다.
Rafał Dowgird

9
zip(ł, ł[1:])훨씬 짧고 pythonic
noɥʇʎԀʎzɐɹƆ

2
@ noɥʇʎԀʎzɐɹƆ : 아니요, 모든 iterable에서 작동하지 않으며 목록에서 사용될 때 불필요한 사본을 만듭니다. 함수를 사용하는 것은 pythonic입니다.
Ry-

이 기능은 funcy모듈 에서 구현됩니다 : funcy.pairwise: funcy.readthedocs.io/en/stable/seqs.html#pairwise
ADR

30

자신의 롤!

def pairwise(iterable):
    it = iter(iterable)
    a = next(it, None)

    for b in it:
        yield (a, b)
        a = b

1
내가 필요한 것! 이것은 파이썬 방법으로 불멸의 상태입니까, 아니면 계속 롤링해야합니까?
uhoh

1
@uhoh : 내가 아는 한 아직!
Ry-

21

때문에 the_list[1:]실제로는 (첫 번째 요소 제외) 전체 목록의 복사본을 생성하고, zip()목록의 총 세 개의 사본이라고 즉시 튜플의 목록을 생성 만들어집니다. 목록이 매우 큰 경우 선호 할 수 있습니다

from itertools import izip, islice
for current_item, next_item in izip(the_list, islice(the_list, 1, None)):
    print(current_item, next_item)

목록을 전혀 복사하지 않습니다.


3
python 3.x에서 izip은 itertools를 제외하고 내장 zip을 사용해야합니다.
Xavier Combelle

1
실제로, the_list[1:]전체 목록을 거의 복사하지 않고 슬라이스 개체를 만드는 것이 아니라 OP의 기술이 사운드를 만드는 것만 큼 낭비가되지는 않습니다.
martineau

3
내가 생각하는 [1:](또는 가능 "슬라이스 객체를 생성 1:")에 전달되는 __slice__만 선택한 요소를 포함하는 사본을 반환 목록에. 목록을 복사하는 관용적 방법 중 하나는 l_copy = l[:](추악하고 읽을 수없는 것을 선호합니다 l_copy = list(l))
dcrosta

4
@dcrosta : __slice__특별한 방법 이 없습니다 . the_list[1:]는에 해당하며 the_list[slice(1, None)], 이는에 해당합니다 list.__getitem__(the_list, slice(1, None)).
Sven Marnach

4
@martineau :에 의해 생성 된 복사본 the_list[1:]은 단순 복사본이므로 목록 항목 당 하나의 포인터로만 구성됩니다. 메모리를 많이 사용하는 부분은 그 zip()자체 tuple입니다. 목록 항목 당 하나의 인스턴스 목록을 작성하기 때문에 각 항목에는 두 항목에 대한 두 개의 포인터와 추가 정보가 포함됩니다. 이 목록은 복사본이 [1:]소비 하는 메모리 양의 9 배를 소비합니다.
Sven Marnach

19

나는 이것을 이것을 내놓고있다. 나는 아무도 enumerate ()에 대해 생각하지 않았다는 것에 놀랐다.

for (index, thing) in enumerate(the_list):
    if index < len(the_list):
        current, next_ = thing, the_list[index + 1]
        #do something

11
실제로, if슬라이싱을 사용하면 다음을 제거 할 수도 있습니다.for (index, thing) in enumerate(the_list[:-1]): current, next_ = thing, the_list[index + 1]
lifebalance

2
이것은 실제로 답이되어야합니다. 추가 수입에 의존하지 않으며 훌륭하게 작동합니다.
jamescampbell

그러나 색인을 생성 할 수없는 이터 러블에는 작동하지 않으므로 일반적인 솔루션이 아닙니다.
wim

14

인덱스로 반복하면 같은 일을 할 수 있습니다.

#!/usr/bin/python
the_list = [1, 2, 3, 4]
for i in xrange(len(the_list) - 1):
    current_item, next_item = the_list[i], the_list[i + 1]
    print(current_item, next_item)

산출:

(1, 2)
(2, 3)
(3, 4)

귀하의 답변은 질문에서와 같이 현재다음 대신에 이전현재 였습니다 . 시맨틱을 개선하여 항상 현재 요소의 색인이 되도록 편집했습니다 . i
Bengt

1

이제는 2020 년 5 월 16 일 현재 간단한 가져 오기입니다.

from more_itertools import pairwise
for current, next in pairwise(your_iterable):
  print(f'Current = {current}, next = {nxt}')

더 많은 도구를위한 문서이 코드는 다른 답변의 코드와 동일하지만 가능한 경우 가져 오기를 선호합니다.

아직 설치하지 않은 경우 : pip install more-itertools

예를 들어, 피본 나치 수열이있는 경우 다음과 같이 후속 쌍의 비율을 계산할 수 있습니다.

from more_itertools import pairwise
fib= [1,1,2,3,5,8,13]
for current, nxt in pairwise(fib):
    ratio=current/nxt
    print(f'Curent = {current}, next = {nxt}, ratio = {ratio} ')

0

목록 이해를 사용하여 목록에서 쌍

the_list = [1, 2, 3, 4]
pairs = [[the_list[i], the_list[i + 1]] for i in range(len(the_list) - 1)]
for [current_item, next_item] in pairs:
    print(current_item, next_item)

산출:

(1, 2)
(2, 3)
(3, 4)

0

난 정말 놀랐 아무도 짧은, 간단하고 가장 중요하게 언급하지 않았다 나는 일반적인 솔루션 :

파이썬 3 :

from itertools import islice

def n_wise(iterable, n):
    return zip(*(islice(iterable, i, None) for i in range(n)))

파이썬 2 :

from itertools import izip, islice

def n_wise(iterable, n):
    return izip(*(islice(iterable, i, None) for i in xrange(n)))

를 전달하여 페어 단위 반복에서 작동 n=2하지만 더 높은 수를 처리 할 수 ​​있습니다.

>>> for a, b in n_wise('Hello!', 2):
>>>     print(a, b)
H e
e l
l l
l o
o !

>>> for a, b, c, d in n_wise('Hello World!', 4):
>>>     print(a, b, c, d)
H e l l
e l l o
l l o
l o   W
o   W o
  W o r
W o r l
o r l d
r l d !

-2

기본 솔루션 :

def neighbors( list ):
  i = 0
  while i + 1 < len( list ):
    yield ( list[ i ], list[ i + 1 ] )
    i += 1

for ( x, y ) in neighbors( list ):
  print( x, y )

-2
code = '0016364ee0942aa7cc04a8189ef3'
# Getting the current and next item
print  [code[idx]+code[idx+1] for idx in range(len(code)-1)]
# Getting the pair
print  [code[idx*2]+code[idx*2+1] for idx in range(len(code)/2)]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.