Python 반복기에서 마지막 항목을 가져 오는 가장 깨끗한 방법


110

Python 2.6의 반복기에서 마지막 항목을 가져 오는 가장 좋은 방법은 무엇입니까? 예를 들어

my_iter = iter(range(5))

지고의 짧은 코드 / 깨끗한 방법은 무엇입니까 4에서는 my_iter?

나는 이것을 할 수 있지만 그것은 매우 효율적이지 않은 것 같습니다.

[x for x in my_iter][-1]

4
반복자는 마지막 요소에 실제로 액세스하지 않고 요소를 반복한다고 가정합니다. 단순히 range (5) [-1]을 사용하지 못하게하는 이유는 무엇입니까?
— Frank

7
@Frank - 나는 실제 반복자가 더 복잡하고 / 또는 더 멀리 및 / 또는 열심히 제어보다이었다 가정iter(range(5))
— 크리스 루츠

3
@Frank : 반복자를 제공하는 것이 실제로 훨씬 더 복잡한 생성기 함수라는 사실. 저는이 예제를 만들어서 무슨 일이 일어나고 있는지 간단하고 명확하게 만들었습니다.
— Peter

4
반복자의 마지막 항목을 원하면 뭔가 잘못하고있을 가능성이 큽니다. 그러나 대답은 반복기를 반복하는 더 깨끗한 방법이 없다는 것입니다. 이는 반복기에 크기가없고 실제로는 전혀 끝나지 않을 수 있으며 마지막 항목이 없을 수도 있기 때문입니다. (물론 코드가 영원히 실행된다는 것을 의미합니다). 그래서 남아있는 질문은 : 왜 반복자의 마지막 항목을 원합니까?
— Lennart Regebro

3
@Peter : 질문을 업데이트 해주세요. 자신이 소유 한 질문에 여러 댓글을 추가하지 마십시오. 질문을 업데이트하고 댓글을 삭제하세요.
— S.Lott

답변:


100
item = defaultvalue
for item in my_iter:
    pass

4
자리 표시자가 "defaultvalue"인 이유는 무엇입니까? 왜 안돼 None? 이것이 바로 그 이유 None입니다. 일부 기능별 기본값이 정확할 수도 있다고 제안하고 있습니까? 반복기가 실제로 반복되지 않으면 대역 외 값이 잘못된 함수 별 기본값보다 더 의미가 있습니다.
— S.Lott

46
기본값은 내 예의 자리 표시 자입니다. None기본값 으로 사용하려는 경우 선택합니다. None은 항상 가장 합리적인 기본값은 아니며 대역 외일 수도 있습니다. 개인적으로 나는 그것이 진정으로 유일한 값인지 확인하기 위해 'defaultvalue = object ()'를 사용하는 경향이 있습니다. 기본 선택이이 예제의 범위를 벗어난다는 것을 나타냅니다.
— Thomas Wouters

28
S. 로트 @ : 아마도 빈 반복자하고있는 반복자의 차이를 구별하는 것이 유용하다 None이 최종 값의로
— 존 라 Rooy

8
모든 내장 컨테이너 유형의 모든 반복기에 디자인 오류가 있습니까? 처음 들었을 때 :)
— Thomas Wouters

7
이것이 아마도 더 빠른 해결책이기는하지만 for-loops (일부 기능, 다른 기능 버그-아마도 FP-guys는 끔찍할 것입니다)에서 변수 누출에 의존합니다. 어쨌든 귀도는 이것이 항상 이런 식으로 작동 할 것이기 때문에 사용하기에 안전한 구조라고 말했다.
— tokland

68

deque크기 1을 사용하십시오 .

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

6
이것은 for 루프보다 약간 빠르지 만 실제로 긴 시퀀스를 소진하는 가장 빠른 방법입니다.
— Sven Marnach 2011 년

11
+1은 기술적으로 정확하지만 독자는 "정말 최적화해야합니까?", "이는 덜 명시 적이며 Pythonic이 아닙니다", "빠른 속도는 구현에 따라 달라집니다. 변경 될 수 있습니다. "
— leewz 2014

1
또한, 그것은 메모리 돼지입니다
— Eelco Hoogendoorn

6
@EelcoHoogendoorn maxlen이 1 인 경우에도 왜 기억에 남을까요?
— Chris Wesseling

1
지금까지 여기에 제시된 모든 솔루션 중에서 이것이 가장 빠르고 가장 메모리 효율적인 솔루션이라는 것을 알았습니다 .
— Markus Strauss

66

Python 3.x를 사용하는 경우 :

*_, last = iterator # for a better understanding check PEP 448
print(last)

Python 2.7을 사용하는 경우 :

last = next(iterator)
for last in iterator:
    continue
print last


참고 :

일반적으로 위에 제시된 솔루션은 일반적인 경우에 필요한 것이지만 대용량 데이터를 처리하는 경우 deque크기 1 을 사용하는 것이 더 효율적 입니다. ( source )

from collections import deque

#aa is an interator
aa = iter('apple')

dd = deque(aa, maxlen=1)
last_element = dd.pop()

1
@virtualxtc : 밑줄은 단지 식별자입니다. 앞에있는 별은 "목록 확장"이라고 말합니다. 더 읽기 쉬운 것은 *lst, last = some_iterable.
— pepr

4
@virtualxtc nope _는 파이썬의 특수 변수이며 마지막 값을 저장하거나 값에 대해 신경 쓰지 않는다고 말할 때 사용됩니다.
— DhiaTN

1
Python 3 솔루션은 메모리 효율적이지 않습니다.
— Markus Strauss

3
@DhiaTN 네, 당신은 절대적으로 옳습니다. 사실 저는 여러분이 많이 보여 주신 Python 3 관용구를 좋아합니다. "빅 데이터"에서는 작동하지 않는다는 점을 분명히하고 싶었습니다. 나는 그것을 위해 collections.deque를 사용하는데, 이는 빠르고 메모리 효율적입니다 (martin23487234의 솔루션 참조).
— Markus Strauss

1
이 py3.5 + 예제는 PEP 448에 있어야합니다. 훌륭합니다.
— EliadL

33

__reversed__가능한 경우 사용할 가치가 있을 것입니다.

if hasattr(my_iter,'__reversed__'):
    last = next(reversed(my_iter))
else:
    for last in my_iter:
        pass

27

다음과 같이 간단합니다.

max(enumerate(the_iter))[1]

8
오, 이것은 영리합니다. 가장 효율적이거나 읽기 쉬운 것은 아니지만 영리합니다.
— timgeb

6
소리내어 생각하면 ... 이것은 다음과 같이 enumerate반환 되기 때문에 작동 합니다 (index, value): (0, val0), (1, val1), (2, val2)... 그리고 max튜플 목록이 주어지면 기본적 으로 튜플의 첫 번째 값과 비교합니다. 인덱스를 나타 내기 때문입니다. 그러면 후행 첨자는 max가 전체 (idx, value) 튜플을 반환하는 반면 우리는 value. 흥미로운 아이디어.
— 테일러 Edmiston

21

이것은 람다로 인해 빈 for 루프보다 빠를 것 같지 않지만 다른 사람에게 아이디어를 줄 수 있습니다.

reduce(lambda x,y:y,my_iter)

iter가 비어 있으면 TypeError가 발생합니다.


IMHO, 이것은 개념적으로 가장 직접적입니다. TypeError빈 이터 러블 을 올리는 대신 초기 값을 통해 기본값을 제공 할 수도 있습니다 ( reduce()예 :) last = lambda iterable, default=None: reduce(lambda _, x: x, iterable, default).
— egnha

9

이거 있어요

list( the_iter )[-1]

반복의 길이가 정말 대단하다면 (너무 길어서 목록을 구체화하면 메모리가 고갈 될 것입니다) 디자인을 다시 생각해야합니다.


1
이것은 가장 간단한 솔루션입니다.
— laike9m

2
튜플을 사용하는 것이 약간 좋습니다.
— Christopher Smith

9
마지막 문장에 매우 동의하지 않습니다. 목록 대신 반복기를 사용하는 주된 이유는 매우 큰 데이터 세트 (한 번에로드되면 메모리 한계를 초과 할 수 있음)로 작업하는 것입니다.
— Paul

@Paul : 일부 함수는 반복자 만 반환합니다. 이것은이 경우에 할 수있는 짧고 읽기 쉬운 방법입니다 (에픽이 아닌 목록의 경우).
— serv-inc

그것은 나쁜 나쁜 습관을 피해야하는 가장 효율적인 방법입니다. 또 다른 방법은 sort (sequence) [-1]을 사용하여 시퀀스의 최대 요소를 가져 오는 것입니다. 소프트웨어 엔지니어가되고 싶다면이 병든 사람들을 절대 사용하지 마십시오.
— Maksym Ganenko

5

reversed다소 임의적으로 보이는 반복자 대신 시퀀스 만 사용 한다는 점을 제외하면을 사용 합니다.

어떤 식 으로든 전체 반복기를 실행해야합니다. 최대 효율에서 반복자가 다시 필요하지 않으면 모든 값을 폐기 할 수 있습니다.

for last in my_iter:
    pass
# last is now the last item

그래도 이것이 차선책이라고 생각합니다.


4
reversed ()는 반복자를 사용하지 않고 시퀀스 만 사용합니다.
— Thomas Wouters

3
그것은 전혀 임의적이지 않습니다. 반복자를 되 돌리는 유일한 방법은 모든 항목을 메모리에 유지하면서 끝까지 반복하는 것입니다. I, e, 당신은 그것을 되돌릴 수 있기 전에 먼저 그것으로부터 시퀀스를 만들어야합니다. 물론 처음에 반복자의 목적을 무너 뜨리고, 명백한 이유없이 갑자기 많은 메모리를 사용하게됩니다. 사실 그것은 임의의 반대입니다. :)
— Lennart Regebro

@Lennart-내가 임의적이라고 말했을 때 나는 성가신 것을 의미했습니다. 나는 아침에 몇 시간 안에 내 논문에 내 언어 능력을 집중하고 있습니다.
— Chris Lutz

3
그럴 수 있지. IMO는 반복자를 받아들이면 더 성 가실 것입니다. 거의 모든 사용이 Bad Idea (tm)이기 때문입니다. :)
— Lennart Regebro

3

툴들은의 라이브러리는 좋은 솔루션을 제공합니다 :

from toolz.itertoolz import last
last(values)

그러나 비 핵심 종속성을 추가하는 것은이 경우에만 사용할 가치가 없을 수 있습니다.



0

나는 그냥 사용합니다 next(reversed(myiter))


8
TypeError : reversed ()에 대한 인수는 시퀀스 여야합니다
— Labo

0

문제는 반복기의 마지막 요소를 가져 오는 것에 관한 것이지만 시퀀스에 조건을 적용하여 반복기가 생성 된 경우 reversed를 사용하여 반전 된 시퀀스의 "첫 번째"를 찾을 수 있습니다. 필요한 요소 만보고 적용하면됩니다. 시퀀스 자체로 되돌립니다.

인위적인 예,

>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8

0

또는 무한 반복자의 경우 다음을 사용할 수 있습니다.

from itertools import islice 
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples 

나는 그것이 더 느릴 것이라고 생각 deque했지만 그것은 빠르며 실제로 for 루프 메서드보다 빠릅니다 (어쨌든)


-6

질문은 잘못되었으며 복잡하고 비효율적 인 답변으로 이어질 수 있습니다. 반복자를 얻으려면 물론 반복 가능한 것부터 시작해야합니다. 대부분의 경우 마지막 요소에 액세스하는보다 직접적인 방법을 제공합니다.

iterable에서 iterator를 생성하면 iterable이 제공하는 유일한 기능이기 때문에 요소를 통과하는 데 갇혀 있습니다.

따라서 가장 효율적이고 명확한 방법은 처음에 반복자를 만드는 것이 아니라 iterable의 기본 액세스 방법을 사용하는 것입니다.


5
그렇다면 파일의 마지막 줄을 어떻게 얻을 수 있습니까?
— Brice M. Dempsey

@ BriceM.Dempsey 가장 좋은 방법은 전체 (아마도 거대 할 수도 있음) 파일을 반복하는 것이 아니라 파일 크기에서 100 바이트를 빼고 마지막 100 바이트를 읽고 새 줄이없는 경우 스캔하는 것입니다. 다른 100 바이트 등을 되돌립니다. 시나리오에 따라 뒤로 가기 크기를 늘릴 수도 있습니다. 무수히 많은 줄을 읽는 것은 확실히 최적이 아닌 해결책입니다.
— Alfe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.