programing

목록의 두 요소마다 반복

goodjava 2023. 1. 14. 09:23

목록의 두 요소마다 반복

★★★★★★★★★★★★★★★★★★★★★★의 작성 방법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

(또는 )의 실장이 필요합니다.

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

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

또는 보다 일반적으로:

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 zip(*[iter(iterable)]*n)

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

Python 2에서는 Python 3의 빌트인 기능을 대체하기 위해 Import해야 합니다.

질문에 대한 답변은 모두 마르티뉴 덕분입니다만, 저는 이것이 매우 효율적이라는 것을 알았습니다.그것은 한 번만 반복되고 그 과정에서 불필요한 목록이 작성하지 않기 때문입니다.

N.B: 이것은 Python 자신의 설명서있는 레시피와 혼동되어서는 안 된다.s -> (s0, s1), (s1, s2), (s2, s3), ...@communr가 댓글로 지적한 바와 같이.

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)

두 가지 요소가 있는 튜플이 필요하기 때문에

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 컬렉션에서 동일한 인덱스 요소로 태플 컬렉션을 만듭니다.
>>> 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']

심플한 솔루션

l = [1, 2, 3, 4, 5, 6]
i 범위(0, len(l), 2)의 경우:str(l[i]), '+', str(l[i + 1]), '=', str(l[i] + l[i + 1])을 인쇄합니다.

은 다 쓰다를 요.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)은 반드시 part part part 、 part 、 part 、 part 、 part 、 part part 。it반복자일 뿐 아니라 반복자이기도 합니다. ifit이미 반복자, 이 라인입니다.이미 반복기이며 이 회선은 no-op입니다.

사용방법:

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

나는 이것이 훨씬 더 우아한 방법이 되기를 바란다.

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

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

퍼포먼스에 관심이 있는 경우를 위해 (라이브러리를 사용하여) 솔루션의 퍼포먼스를 비교하기 위해 작은 벤치마크를 실시하여 패키지 중 하나에 포함된 기능을 포함시켰습니다.

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의 접근방식을 사용하는 것이 좋습니다(작성 시점에서는 가장 높은 투표율로 받아들여지고 있습니다).

If you don't mind the additional dependency then the 추가 종속성을 개의치 않으신다면grouper부에서iteration_utilities아마도 조금 더 빨리 될 거예요.조금 더 빠를 것 같아요.

기타 생각

일부 접근 방식에는 몇 가지 제한이 있지만, 여기서는 설명하지 않았습니다.

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

그리고 존은 또 다른 대답을 하지 않는 반면, john 그 루 은,개 the사 answers로즈 john then이 alsoys동 provided don이 the 2 for while that sizes' ( than의web션 otheryst다른 답변은 그렇지 않습니다(좋습니다.iteration_utilities.grouper또, 요소의 수를 「그룹」으로 설정할 수도 있습니다).

그리고 목록에 홀수 개수의 요소가 있을 경우 어떤 일이 일어나야 하는지에 대한 질문도 있습니다.나머지 아이템은 폐기해야 합니까?목록을 같은 크기로 만들기 위해 패딩해야 할까요?나머지 상품은 1개로 반품해야 합니까?다른 답변은 이 점을 직접적으로 다루지는 않지만, 제가 간과하지 않은 항목이 있으면 모두 나머지 항목을 폐기해야 한다는 접근방식을 따릅니다(태스크누터의 답변은 예외입니다).

★★★★★★★★★★★★★★★★ 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)]

하다를 사용하세요.zip ★★★★★★★★★★★★★★★★★」iter다음 중 하나:

이 해결 방법은 다음과 같습니다.iter: 아아우:::::::

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

Python 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)]
for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k

zip(*iterable)각 반복 가능한 다음 요소가 포함된 태플을 반환합니다.

l[::2]목록의 첫 번째, 세 번째, 다섯 번째 요소를 반환합니다.첫 번째 콜론은 뒤에 숫자가 없기 때문에 슬라이스가 시작되었음을 나타냅니다.두 번째 콜론은 '슬라이스 스텝 인'을 원하는 경우에만 필요합니다(이 경우 2).

l[1::2]는 같은 작업을 수행하지만 목록의 두 번째 요소부터 시작하므로 원래 목록의 두 번째, 네 번째, 여섯 번째, 여섯 번째 요소를 반환합니다.

개봉 시:

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

은 소비됩니다.l나중에 비워두면 됩니다.

그것을 하는 방법은 여러 가지가 있다.예를 들어 다음과 같습니다.

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)]

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

import more_itertools

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

(서로 배타적인 쌍이 아닌) 쌍이 겹치는 유사한 문제에 대한 해결책을 다음에 제시하겠습니다.

Python 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)

이 질문의 제목은 오해의 소지가 있어 연속된 쌍을 찾고 있는 것 같습니다만, 가능한 모든 쌍의 집합에 대해 반복하는 경우는, 다음과 같이 됩니다.

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

심플한 어프로치:

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

이는 어레이가 의 경우 쌍으로 반복하려는 경우에 유용합니다.트리플렛 이상에서 반복하려면 "range" 단계 명령을 다음과 같이 변경하십시오.

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

(어레이의 길이와 순서가 맞지 않는 경우는, 초과치에 대처할 필요가 있습니다).

세련된 Python3 솔루션은 다음 중 하나에 포함되어 있습니다.itertools 레시피:

import itertools

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(*args, fillvalue=fillvalue)

청정 솔루션 재도전

def grouped(itr, n=2):
    itr = iter(itr)
    end = object()
    while True:
        vals = tuple(next(itr, end) for _ in range(n))
        if vals[-1] is end:
            return
        yield vals

커스터마이즈 옵션 추가

from collections.abc import Sized

def grouped(itr, n=2, /, truncate=True, fillvalue=None, strict=False, nofill=False):
    if strict:
        if isinstance(itr, Sized):
            if len(itr) % n != 0:
                raise ValueError(f"{len(itr)=} is not divisible by {n=}")
    itr = iter(itr)
    end = object()
    while True:
        vals = tuple(next(itr, end) for _ in range(n))
        if vals[-1] is end:
            if vals[0] is end:
                return
            if strict:
                raise ValueError("found extra stuff in iterable")
            if nofill:
                yield tuple(v for v in vals if v is not end)
                return
            if truncate:
                return
            yield tuple(v if v is not end else fillvalue for v in vals)
            return
        yield vals

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)

리스트를 숫자로 나눠서 이렇게 고정해야 해요.

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]]

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

여기서 우리는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)

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

이것은 레인지 함수를 사용하여 요소 목록에서 대체 요소를 선택하는 간단한 솔루션입니다.

주의: 짝수 목록에 대해서만 유효합니다.

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)
# [3, 7, 11]

언급URL : https://stackoverflow.com/questions/5389507/iterating-over-every-two-elements-in-a-list