목록의 두 요소마다 반복


209

어떻게 내가 어떻게해야합니까 for루프 또는 모든 반복이 나에게 두 가지 요소를 제공하도록 지능형리스트를?

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

for i,k in ???:
    print str(i), '+', str(k), '=', str(i+k)

산출:

1+2=3
3+4=7
5+6=11

답변:


231

pairwise()(또는 grouped()) 구현 이 필요합니다 .

파이썬 2의 경우 :

from itertools import izip

def pairwise(iterable):
    "s -> (s0, s1), (s2, s3), (s4, s5), ..."
    a = iter(iterable)
    return izip(a, a)

for x, y in pairwise(l):
   print "%d + %d = %d" % (x, y, x + y)

또는 더 일반적으로 :

from itertools import izip

def grouped(iterable, n):
    "s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
    return izip(*[iter(iterable)]*n)

for x, y in grouped(l, 2):
   print "%d + %d = %d" % (x, y, x + y)

Python 3에서는 izip내장 zip()함수로 대체하고을 삭제할 수 import있습니다.

내 질문에 대한 그의 답변 에 대한 마 티노에 대한 모든 신용 은 목록을 한 번만 반복하고 프로세스에서 불필요한 목록을 만들지 않기 때문에 이것이 매우 효율적이라는 것을 알았습니다.

NB는 :이은과 혼동해서는 안 pairwise조리법 파이썬의 자신의 itertools문서 , 수율 s -> (s0, s1), (s1, s2), (s2, s3), ...에 의해 지적 밖으로로서, @lazyr 의견이다.

Python 3 에서 mypy로 유형 검사를하고 싶은 사람들에게는 거의 추가되지 않습니다 .

from typing import Iterable, Tuple, TypeVar

T = TypeVar("T")

def grouped(iterable: Iterable[T], n=2) -> Iterable[Tuple[T, ...]]:
    """s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""
    return zip(*[iter(iterable)] * n)

16
에서 제안 쌍대 함수와 혼동하지 itertools 되는 수율 레시피 섹션s -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow

1
다른 일을합니다. itertools동일한 버전의 레시피 기능과 비교하여 버전의 절반 만 생산합니다 . 물론 당신은 더 빠릅니다 ...
Sven Marnach

응? 당신의 기능과 내가 언급 한 기능은 다른 일을했으며 그것이 저의 의견이었습니다.
Lauritz V. Thaulow

5
조심해! 이 함수를 사용하면 iterable의 마지막 요소를 반복하지 않을 위험이 있습니다. 예 : list (grouped ([1,2,3], 2)) >>> [(1, 2)] .. [(1,2), (3,)]
egafni

4
@ Erik49 : 질문에 지정된 경우 '불완전한'튜플을 갖는 것은 의미가 없습니다. 불완전한 튜플을 포함하려면 izip_longest()대신 대신 사용할 수 있습니다 izip(). 예 : list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. 도움이 되었기를 바랍니다.
Johnsyweb

191

두 요소의 튜플이 필요합니다.

data = [1,2,3,4,5,6]
for i,k in zip(data[0::2], data[1::2]):
    print str(i), '+', str(k), '=', str(i+k)

어디:

  • data[0::2] 요소의 하위 집합 모음을 만드는 것을 의미합니다. (index % 2 == 0)
  • zip(x,y) x 및 y 컬렉션에서 동일한 인덱스 요소로 튜플 컬렉션을 만듭니다.

8
두 개 이상의 요소가 필요한 경우에도 확장 할 수 있습니다. 예를 들어for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
수명 균형

19
가져 오기를 가져 와서 함수를 정의하는 것보다 훨씬 깨끗합니다!
kmarsh

7
@ kmarsh : 그러나 이것은 시퀀스에서만 작동하며 함수는 모든 반복 가능에서 작동합니다. 그리고 이것은 O (N) 여분의 공간을 사용하지만 함수는 그렇지 않습니다. 반면에 이것은 일반적으로 더 빠릅니다. 둘 중 하나를 선택해야 할 이유가 있습니다. 두려워하는 import것은 그들 중 하나가 아닙니다.
abarnert

77
>>> l = [1,2,3,4,5,6]

>>> zip(l,l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

>>> zip(l,l[1:])[::2]
[(1, 2), (3, 4), (5, 6)]

>>> [a+b for a,b in zip(l,l[1:])[::2]]
[3, 7, 11]

>>> ["%d + %d = %d" % (a,b,a+b) for a,b in zip(l,l[1:])[::2]]
['1 + 2 = 3', '3 + 4 = 7', '5 + 6 = 11']

1
이것은 파이썬 3.6.0 작업하지만 여전히 파이썬 2.7.10에서 작동하지 않습니다
하미드로하니

6
@HamidRohani zipzipPython 3에서 개체를 반환하며 , 첨자는 불가능합니다. 먼저 시퀀스 ( list, tuple등) 로 변환해야 하지만 "작동하지 않음" 은 약간의 확장입니다.
vaultah

58

간단한 해결책.

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

범위 (i, len (l), 2)의 i의 경우 :
    str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1]) 인쇄

1
목록이 고르지 않고 마지막 숫자를 그대로 표시하려면 어떻게해야합니까?
Hans de Jong

@HansdeJong은 당신을 얻지 못했습니다. 좀 더 설명해주세요.
taskinoor

2
감사. 나는 그것을하는 방법을 이미 알아 냈습니다. 문제는 목록에 숫자가없는 목록이 있으면 색인 오류가 발생한다는 것입니다. 시도와 함께 해결 : 예외 :
한스 드 종

또는 ((l[i], l[i+1])for i in range(0, len(l), 2))발전기의 경우 더 긴 튜플을 위해 쉽게 수정할 수 있습니다.
바젤 시사 니

44

사용하는 모든 답변 zip이 정확 하지만 기능을 직접 구현하면 더 읽기 쉬운 코드로 연결됩니다.

def pairwise(it):
    it = iter(it)
    while True:
        try:
            yield next(it), next(it)
        except StopIteration:
            # no more elements in the iterator
            return

it = iter(it)부분은 it반복 가능한 것이 아니라 실제로 반복자 임을 보장합니다 . 경우 it이미이 반복자이며,이 라인은 no-op입니다.

용법:

for a, b in pairwise([0, 1, 2, 3, 4, 5]):
    print(a + b)

2
이 솔루션은 튜플의 크기> 2로 일반화 할 수 있습니다
guilloptero

1
이 솔루션 it은 반복자 일 뿐이고 반복 가능하지 않은 경우에도 작동합니다 . 다른 솔루션은 시퀀스에 대해 두 개의 독립적 인 반복자를 만들 가능성에 의존하는 것 같습니다.
skyking

이 답변을보기 전에 stackoverflow.com/a/16815056/2480481 에서이 방법을 찾았습니다 . zip ()을 다루는 것보다 깨끗하고 쉽습니다.
m3nda 2016 년

2
나는 그것이 삼중 메모리 사용을 허용되는 대답으로 피할 수 있다는 것을 좋아합니다.
Kentzo

이와 함께 잘 작동하지 않습니다 for인해 파이썬에서 루프 3.5 PEP 479 어떤 대체 StopIteration기호가있는 발전기에서 제기 RuntimeError.
sidney

28

나는 이것이 더 우아한 방법이되기를 바랍니다.

a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])

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

18

성능에 관심이있는 경우 simple_benchmark솔루션의 성능을 비교하기 위해 작은 벤치 마크 (내 라이브러리 사용 )를 수행했으며 패키지 중 하나의 기능을 포함했습니다.iteration_utilities.grouper

from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark import BenchmarkBuilder

bench = BenchmarkBuilder()

@bench.add_function()
def Johnsyweb(l):
    def pairwise(iterable):
        "s -> (s0, s1), (s2, s3), (s4, s5), ..."
        a = iter(iterable)
        return zip(a, a)

    for x, y in pairwise(l):
        pass

@bench.add_function()
def Margus(data):
    for i, k in zip(data[0::2], data[1::2]):
        pass

@bench.add_function()
def pyanon(l):
    list(zip(l,l[1:]))[::2]

@bench.add_function()
def taskinoor(l):
    for i in range(0, len(l), 2):
        l[i], l[i+1]

@bench.add_function()
def mic_e(it):
    def pairwise(it):
        it = iter(it)
        while True:
            try:
                yield next(it), next(it)
            except StopIteration:
                return

    for a, b in pairwise(it):
        pass

@bench.add_function()
def MSeifert(it):
    for item1, item2 in grouper(it, 2):
        pass

bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1, 20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize'] = (8, 10)
benchmark_result.plot_both(relative_to=MSeifert)

여기에 이미지 설명을 입력하십시오

따라서 외부 의존성이없는 가장 빠른 솔루션을 원한다면 Johnysweb이 제공 한 접근 방식을 사용해야합니다 (작성 시점에서 가장 찬성되고 인정 된 답변입니다).

추가 종속성을 신경 쓰지 않으면 grouperfrom iteration_utilities이 약간 빠를 것입니다.

추가 생각

일부 접근 방식에는 여기에서 설명하지 않은 제한 사항이 있습니다.

예를 들어, 일부 솔루션은 시퀀스 (즉, 목록, 문자열 등)에만 작동합니다. 예를 들어 Margus / pyanon / taskinoor 솔루션은 인덱싱을 사용하고 다른 솔루션은 Johnysweb /과 같은 반복 가능 (시퀀스 생성기, 반복기)에서 작동합니다. mic_e / my 솔루션.

그런 다음 Johnysweb은 2 이외의 다른 크기에서도 작동하는 솔루션을 제공했지만 다른 답변은 그렇지 않습니다 ( iteration_utilities.grouper요소 수를 "그룹"으로 설정할 수도 있음).

그런 다음 목록에 홀수 개의 요소가있는 경우 어떻게해야하는지에 대한 질문도 있습니다. 나머지 품목을 기각해야합니까? 크기가 일정하도록 목록을 채워야합니까? 나머지 품목을 단일 품목으로 반품해야합니까? 다른 대답은이 요점을 직접 다루지 않지만, 아무것도 간과하지 않은 경우 나머지 항목을 무시 해야하는 접근법을 따르지 않습니다 (실무자가 답변을 제외하고 실제로 예외가 발생 함).

으로 grouper당신은 당신이 원하는 무엇을 결정할 수 있습니다 :

>>> from iteration_utilities import grouper

>>> list(grouper([1, 2, 3], 2))  # as single
[(1, 2), (3,)]

>>> list(grouper([1, 2, 3], 2, truncate=True))  # ignored
[(1, 2)]

>>> list(grouper([1, 2, 3], 2, fillvalue=None))  # padded
[(1, 2), (3, None)]

12

zipiter명령을 함께 사용하십시오 .

이 솔루션을 사용 iter하여 매우 우아하다고 생각합니다.

it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]

파이썬 3 zip 문서 에서 찾은 것입니다 .

it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')

# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11

N한 번 에 요소 를 일반화하려면 다음을 수행하십시오.

N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]

10
for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k

zip(*iterable) 각 iterable의 다음 요소와 함께 튜플을 반환합니다.

l[::2] 목록의 첫 번째, 세 번째, 다섯 번째 등 요소를 반환합니다. 첫 번째 콜론은 슬라이스 뒤에 숫자가 없기 때문에 슬라이스가 처음부터 시작 함을 나타내며 두 ​​번째 콜론은 슬라이스의 '단계'를 원할 경우에만 필요합니다 '(이 경우 2).

l[1::2]동일한 작업을 수행하지만 목록의 두 번째 요소에서 시작하므로 원래 목록 의 2, 4, 6 등을 반환 합니다.


4
이 답변은 이미 2 년 전에 Margus에 의해 제공되었습니다. stackoverflow.com/questions/5389507/…
cababunga 2012 년

1
[number::number]구문 작동 방식을 설명하는 1입니다 . 파이썬을 자주 사용하지 않는 사람에게 도움이 됨
Alby

2

포장 풀기 :

l = [1,2,3,4,5,6]
while l:
    i, k, *l = l
    print(str(i), '+', str(k), '=', str(i+k))

와! 내가 이것에 대해 생각할 수 없었던 이유 :) 당신은 절대 쌍 (홀수 엔트리)이없는 경우를 처리해야합니다
Saurav Kumar

1

누구나 도움이 될 수 있지만 여기에는 비슷한 문제이지만 겹치는 쌍 (상호 배타적 쌍 대신)이있는 해결책이 있습니다.

파이썬 itertools 문서에서 :

from itertools import izip

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

또는 더 일반적으로 :

from itertools import izip

def groupwise(iterable, n=2):
    "s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
    t = tee(iterable, n)
    for i in range(1, n):
        for j in range(0, i):
            next(t[i], None)
    return izip(*t)

1

more_itertools 패키지 를 사용할 수 있습니다 .

import more_itertools

lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
    print(f'{i} + {j} = {i+j}')

1

목록을 숫자로 나누고 이와 같이 수정해야합니다.

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

def divideByN(data, n):
        return [data[i*n : (i+1)*n] for i in range(len(data)//n)]  

>>> print(divideByN(l,2))
[[1, 2], [3, 4], [5, 6]]

>>> print(divideByN(l,3))
[[1, 2, 3], [4, 5, 6]]

1

여러 가지 방법이 있습니다. 예를 들면 다음과 같습니다.

lst = [1,2,3,4,5,6]
[(lst[i], lst[i+1]) for i,_ in enumerate(lst[:-1])]    
>>>[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

[i for i in zip(*[iter(lst)]*2)]    
>>>[(1, 2), (3, 4), (5, 6)]

0

이것은 n> 2에 대한 일반화를 공유하기에 좋은 장소라고 생각했습니다.

def sliding_window(iterable, n):
    its = [ itertools.islice(iter, i, None) 
            for i, iter
            in enumerate(itertools.tee(iterable, n)) ]                               

    return itertools.izip(*its)

0

이 질문의 제목은 오해의 소지가 있습니다. 연속 쌍을 찾고있는 것 같지만 가능한 모든 쌍 세트를 반복하려면 다음과 같이하십시오.

for i,v in enumerate(items[:-1]):
        for u in items[i+1:]:

0

타이핑을 사용하여 mypy 정적 분석 도구를 사용하여 데이터를 확인할 수 있습니다 .

from typing import Iterator, Any, Iterable, TypeVar, Tuple

T_ = TypeVar('T_')
Pairs_Iter = Iterator[Tuple[T_, T_]]

def legs(iterable: Iterator[T_]) -> Pairs_Iter:
    begin = next(iterable)
    for end in iterable:
        yield begin, end
        begin = end

0

간단한 접근 방식 :

[(a[i],a[i+1]) for i in range(0,len(a),2)]

이것은 배열이 a이고 쌍으로 반복하려는 경우 유용합니다. 트리플렛 이상에서 반복하려면 "range"단계 명령을 변경하십시오. 예를 들면 다음과 같습니다.

[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]

(배열 길이와 단계가 맞지 않으면 초과 값을 처리해야합니다)


-1

여기에 alt_elemfor 루프에 맞는 방법을 사용할 수 있습니다.

def alt_elem(list, index=2):
    for i, elem in enumerate(list, start=1):
        if not i % index:
           yield tuple(list[i-index:i])


a = range(10)
for index in [2, 3, 4]:
    print("With index: {0}".format(index))
    for i in alt_elem(a, index):
       print(i)

산출:

With index: 2
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
With index: 3
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
With index: 4
(0, 1, 2, 3)
(4, 5, 6, 7)

참고 : 위의 솔루션은 기능에서 수행되는 작업을 고려할 때 효율적이지 않을 수 있습니다.


-1
a_list = [1,2,3,4,5,6]
empty_list = [] 
for i in range(0,len(a_list),2):
   empty_list.append(a_list[i]+a_list[i+1])   
print(empty_list)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.