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.