개발/Python

쌍을 이루는 순환 파이썬 'for'루프

MinorMan 2021. 4. 20. 03:32
반응형

<질문>

한 쌍의 요소를 다시 조정하여 목록을 반복하는 멋진 Python 방법이 있습니까? 마지막 요소는 첫 번째 요소와 쌍을 이루어야합니다.

예를 들어 [1, 2, 3] 목록이있는 경우 다음 쌍을 얻고 싶습니다.

  • 1 ~ 2
  • 2 ~ 3
  • 3-1

<답변1>

쌍으로 목록에 액세스하는 Python 방식은 다음과 같습니다.zip(L, L[1:]). 마지막 항목을 첫 번째 항목에 연결하려면 :

>>> L = [1, 2, 3]
>>> zip(L, L[1:] + L[:1])
[(1, 2), (2, 3), (3, 1)]

<답변2>

나는dequezip이것을 달성하기 위해.

>>> from collections import deque
>>>
>>> l = [1,2,3]
>>> d = deque(l)
>>> d.rotate(-1)
>>> zip(l, d)
[(1, 2), (2, 3), (3, 1)]

<답변3>

나는 약간의 수정을 사용합니다pairwise레시피에서itertools documentation:

def pairwise_circle(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ... (s,s0)"
    a, b = itertools.tee(iterable)
    first_value = next(b, None)
    return itertools.zip_longest(a, b,fillvalue=first_value)

이것은 단순히 첫 번째 값에 대한 참조를 유지하고 두 번째 반복자가 소진되면zip_longest마지막 자리를 첫 번째 값으로 채 웁니다.

(또한 생성기와 같은 반복기뿐만 아니라 목록 / 튜플과 같은 반복자에서도 작동합니다.)

참고@Barry's solution이것과 매우 유사하지만 제 생각에는 이해하기가 더 쉽고 한 요소 이상으로 확장하기가 더 쉽습니다.


<답변4>

나는 페어링 할 것이다itertools.cyclezip:

import itertools

def circular_pairwise(l):
    second = itertools.cycle(l)
    next(second)
    return zip(l, second)

cycle마지막 값에서 첫 번째 값으로 반복하면서 인수의 값을 순서대로 생성하는 iterable을 반환합니다.

첫 번째 값을 건너 뛰므로 위치에서 시작합니다.1(보단0).

다음으로zip원래의 변형되지 않은 목록과 함께.zip인수 iterable이 소진되면 중지되기 때문에 좋습니다.

이렇게하면 중간 목록이 생성되지 않습니다.cycle원본에 대한 참조를 보유하지만 복사하지는 않습니다.zip같은 방식으로 작동합니다.

입력이 인 경우 중단된다는 점에 유의하는 것이 중요합니다.iterator, 과 같은file, (또는map또는zip), 한곳에서 (next(second))는 다른 모든 항목에서 자동으로 반복기를 진행합니다. 이것은 다음을 사용하여 쉽게 해결됩니다.itertools.tee, 원래 이터 러블에 대해 두 개의 독립적으로 작동하는 이터레이터를 생성합니다.

def circular_pairwise(it):
    first, snd = itertools.tee(it)
    second = itertools.cycle(snd)
    next(second)
    return zip(first, second)

tee할 수있다예를 들어, 반환 된 반복기 중 하나가 다른 하나를 건 드리기 전에 다 사용 된 경우 많은 양의 추가 저장소를 사용하지만 한 단계 차이 만 있기 때문에 추가 저장소가 최소화됩니다.


<답변5>

더 효율적인 방법 (임시 목록을 작성하지 않음)이 있지만 이것이 가장 간결하다고 생각합니다.

> l = [1,2,3]
> zip(l, (l+l)[1:])
[(1, 2), (2, 3), (3, 1)]

<답변6>

나는 목록 이해력을 사용하고l[-1]마지막 요소입니다.

>>> l = [1,2,3]
>>> [(l[i-1],l[i]) for i in range(len(l))]
[(3, 1), (1, 2), (2, 3)]

그런 식으로 임시 목록이 필요하지 않습니다.


<답변7>

쌍을 이루는 순환 파이썬 'for'루프

수락 된 답변이 마음에 들면

zip(L, L[1:] + L[:1])

의미 상 동일한 코드로 훨씬 더 많은 메모리 라이트를 사용할 수 있습니다.itertools:

from itertools import islice, chain #, izip as zip # uncomment if Python 2

그리고 이것은 원래 목록 이외의 메모리에있는 모든 것을 거의 구체화하지 않습니다 (목록이 상대적으로 크다고 가정).

zip(l, chain(islice(l, 1, None), islice(l, None, 1)))

사용하려면 다음과 같이 소비하십시오 (예 : 목록 사용).

>>> list(zip(l, chain(islice(l, 1, None), islice(l, None, 1))))
[(1, 2), (2, 3), (3, 1)]

이것은 모든 너비로 확장 가능하게 만들 수 있습니다.

def cyclical_window(l, width=2):
    return zip(*[chain(islice(l, i, None), islice(l, None, i)) for i in range(width)])

및 사용법 :

>>> l = [1, 2, 3, 4, 5]
>>> cyclical_window(l)

>>> list(cyclical_window(l))
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
>>> list(cyclical_window(l, 4))
[(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 1), (4, 5, 1, 2), (5, 1, 2, 3)]

당신은 또한 사용할 수 있습니다tee중복 순환 객체를 만들지 않으려면 :

from itertools import cycle, tee
ic1, ic2 = tee(cycle(l))
next(ic2)    # must still queue up the next item

그리고 지금:

>>> [(next(ic1), next(ic2)) for _ in range(10)]
[(1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2)]

이것은 매우 효율적이며 예상되는 용도iternext, 우아한 사용법cycle,tee, 및zip.

통과하지 마십시오cycle직접list작업을 저장하지 않았고 메모리를 최대로 사용하여 컴퓨터가 정지 할 시간이없는 경우-운이 좋으면 잠시 후 OS가 컴퓨터를 중단하기 전에 프로세스를 종료합니다.

마지막으로 표준 lib 가져 오기는 없지만 원본 목록의 길이까지만 작동합니다 (그렇지 않으면 IndexError).

>>> [(l[i], l[i - len(l) + 1]) for i in range(len(l))]
[(1, 2), (2, 3), (3, 1)]

모듈로를 사용하여 계속할 수 있습니다.

>>> len_l = len(l)
>>> [(l[i % len_l], l[(i + 1) % len_l]) for i in range(10)]
[(1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2)]

<답변8>

이 문제를 해결하는 방법이 얼마나 많은지 놀랍습니다.

여기 하나 더 있습니다. 사용할 수 있습니다pairwise레시피로 압축하는 대신b,chain이미 튀어 나온 첫 번째 요소와 함께. 그럴 필요 없어cycle하나의 추가 값이 필요할 때 :

from itertools import chain, izip, tee

def pairwise_circle(iterable):
    a, b = tee(iterable)
    first = next(b, None)
    return izip(a, chain(b, (first,)))

<답변9>

원래 목록을 수정하지 않고 임시 저장소에 목록을 복사하지 않는 솔루션을 좋아합니다.

def circular(a_list):
    for index in range(len(a_list) - 1):
        yield a_list[index], a_list[index + 1]
    yield a_list[-1], a_list[0]

for x in circular([1, 2, 3]):
    print x

산출:

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

나는 이것이 매우 큰 메모리 내 데이터에 사용되는 것을 상상할 수 있습니다.


<답변10>

이것은 목록이l시스템 메모리의 대부분을 소비했습니다. (무언가이 사건이 불가능하다고 보장한다면, chepner가 게시 한대로 zip을 사용해도됩니다)

l.append( l[0] )
for i in range( len(l)-1):
   pair = l[i],l[i+1]
   # stuff involving pair
del l[-1] 

또는 더 일반적으로 (모든 오프셋에 대해 작동nl[ (i+n)%len(l) ])

for i in range( len(l)):
   pair = l[i], l[ (i+1)%len(l) ]
   # stuff

모듈로 분할이 상당히 빠른 시스템 (즉, 일부 완두콩 내장 시스템이 아님)을 사용하는 경우.

정수 첨자로 목록을 인덱싱하는 것은 비 파이썬 적이며 피하는 것이 가장 좋다는 믿음이 자주있는 것 같습니다. 왜?


<답변11>

이것은 내 솔루션이며 나에게 충분히 Pythonic으로 보입니다.

l = [1,2,3]

for n,v in enumerate(l):
    try:
        print(v,l[n+1])
    except IndexError:
        print(v,l[0])

인쇄물:

1 2
2 3
3 1

생성기 기능 버전 :

def f(iterable):
    for n,v in enumerate(iterable):
        try:
            yield(v,iterable[n+1])
        except IndexError:
            yield(v,iterable[0])

>>> list(f([1,2,3]))
[(1, 2), (2, 3), (3, 1)]

<답변12>

이건 어때요?

li = li+[li[0]]
pairwise = [(li[i],li[i+1]) for i in range(len(li)-1)]

<답변13>

from itertools import izip, chain, islice

itr = izip(l, chain(islice(l, 1, None), islice(l, 1)))

(위와 같이@j-f-sebastian's "zip" answer,하지만 itertools를 사용합니다.)

주의 :편집 됨도움이되는@200_success. 이전 :

itr = izip(l, chain(l[1:], l[:1]))

<답변14>

또 다른 시도

>>> L = [1,2,3]
>>> zip(L,L[1:]) + [(L[-1],L[0])]
[(1, 2), (2, 3), (3, 1)]

<답변15>

너무 많은 메모리를 소비하지 않으려면 내 솔루션을 시도해 볼 수 있습니다.

[(l[i], l[(i+1) % len(l)]) for i, v in enumerate(l)]

조금 느리지 만 메모리를 덜 소비합니다.


<답변16>

Python 3.10release schedule, 새로운pairwise함수는 연속 요소의 슬라이딩 쌍을 만드는 방법을 제공합니다.

from itertools import pairwise

# l = [1, 2, 3]
list(pairwise(l + l[:1]))
# [(1, 2), (2, 3), (3, 1)]

또는 간단히pairwise(l + l[:1])결과가 필요하지 않은 경우list.

우리는pairwise머리 (l + l[:1]) 롤링 쌍이 원형이되도록 (즉,(3, 1)쌍):

list(pairwise(l)) # [(1, 2), (2, 3)]
l + l[:1] # [1, 2, 3, 1]

<답변17>

L = [1, 2, 3] a = zip (L, L [1 :] + L [: 1]) for i in a : b = list (i) print b


<답변18>

이것은 조합이 일을 할 것 같습니다.

from itertools import combinations
x=combinations([1,2,3],2)

이것은 발전기를 산출 할 것입니다. 그런 다음 반복 할 수 있습니다.

for i in x:
  print i

결과는 다음과 같습니다.

(1, 2)
(1, 3)
(2, 3)
반응형