Câu hỏi Cách tốt nhất để lấy mục cuối cùng từ trình lặp Python


Cách tốt nhất để lấy mục cuối cùng từ một trình lặp trong Python 2.6 là gì? Ví dụ: nói

my_iter = iter(range(5))

Cách ngắn nhất để nhận được mã / cách sạch nhất 4 từ my_iter?

Tôi có thể làm điều này, nhưng nó có vẻ không hiệu quả lắm:

[x for x in my_iter][-1]

76
2018-01-26 10:53


gốc


Các Iterator giả định rằng bạn muốn lặp qua các phần tử và không truy cập các phần tử cuối cùng thực sự. Điều gì khiến bạn ngừng sử dụng phạm vi (5) [- 1]? - Frank
@Frank - Tôi cho rằng trình lặp thực tế phức tạp hơn và / hoặc xa hơn và / hoặc khó kiểm soát hơn iter(range(5)) - Chris Lutz
@Frank: thực tế là nó thực sự là một chức năng tạo phức tạp hơn nhiều, cung cấp cho trình vòng lặp. Tôi chỉ làm ví dụ này để nó đơn giản và rõ ràng những gì đang xảy ra. - Peter
Nếu bạn muốn mục cuối cùng của một iterator, có một cơ hội lớn bạn đang làm gì đó sai. Nhưng câu trả lời là không có cách nào thực sự sạch hơn mà lặp qua trình lặp. Điều này là do các trình vòng lặp không có kích thước, và trên thực tế, có thể không bao giờ kết thúc, và vì vậy có thể không có một mục cuối cùng. (Có nghĩa là mã của bạn sẽ chạy mãi mãi, tất nhiên). Vì vậy, câu hỏi kéo dài là: Tại sao bạn muốn mục cuối cùng của một trình lặp? - Lennart Regebro
@Peter: Hãy cập nhật câu hỏi của bạn. Không thêm một loạt nhận xét vào câu hỏi mà bạn sở hữu. Vui lòng cập nhật câu hỏi và xóa nhận xét. - S.Lott


Các câu trả lời:


item = defaultvalue
for item in my_iter:
    pass

70
2018-01-26 10:56



Tại sao trình giữ chỗ "defaultvalue"? Tại sao không None? Đây chính xác là những gì None là cho. Bạn có gợi ý rằng một số giá trị mặc định của hàm cụ thể thậm chí có thể chính xác không? Nếu trình vòng lặp không thực sự lặp lại, thì giá trị ngoài băng là hơn có ý nghĩa hơn một số mặc định về chức năng gây hiểu lầm cụ thể. - S.Lott
Giá trị mặc định chỉ là một trình giữ chỗ cho ví dụ của tôi. Nếu bạn muốn sử dụng None là giá trị mặc định, đó là lựa chọn của bạn. Không phải lúc nào cũng không phải là mặc định hợp lý nhất, và thậm chí không thể ra khỏi ban nhạc. Cá nhân tôi có xu hướng sử dụng 'defaultvalue = object ()' để đảm bảo nó là một giá trị thực sự duy nhất. Tôi chỉ cho biết rằng lựa chọn mặc định nằm ngoài phạm vi của ví dụ này. - Thomas Wouters
@ S.Lott: có lẽ nó rất hữu ích để phân biệt sự khác biệt giữa một iterator rỗng và một iterator có None vì nó là giá trị cuối cùng - John La Rooy
Có một lỗi thiết kế trong tất cả các trình lặp của tất cả các loại thùng chứa dựng sẵn? Lần đầu tiên tôi nghe nói về nó :) - Thomas Wouters
Trong khi điều này có lẽ là giải pháp nhanh hơn, nó dựa trên biến rò rỉ trong vòng lặp (một tính năng cho một số, một lỗi cho những người khác - có lẽ FP-guys đang kinh hoàng). Dù sao đi nữa, Guido nói rằng điều này sẽ luôn luôn hoạt động theo cách này, vì vậy nó được xây dựng an toàn để sử dụng. - tokland


Sử dụng một deque kích thước 1.

from collections import deque

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

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

41
2017-07-02 23:39



Đây thực sự là cách nhanh nhất để xả một chuỗi dài, mặc dù chỉ slighlty nhanh hơn vòng lặp for. - Sven Marnach
1 cho là chính xác về mặt kỹ thuật, nhưng độc giả nên có các thông thường Python caveats, "Bạn có thực sự cần phải tối ưu hóa này?", "Đây là ít rõ ràng, mà không phải là Pythonic", và "Tốc độ nhanh hơn phụ thuộc vào thực hiện, có thể thay đổi." - leewz
Ngoài ra, nó là một bộ nhớ-hog - Eelco Hoogendoorn
@EelcoHoogendoorn Tại sao nó là một bộ nhớ-hog, ngay cả với một maxlen của 1? - Chris Wesseling


Có thể đáng sử dụng __reversed__ nếu nó có sẵn

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

29
2018-02-05 23:01





Nếu bạn đang sử dụng python 3.x:

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

nếu bạn đang sử dụng python 2.7:

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

22
2018-01-12 19:07



Bạn có thể giải thích *_ phần? - virtualxtc
@virtualxtc check PEP 448 để biết thêm chi tiết - DhiaTN
@virtualxtc: Dấu gạch dưới chỉ là số nhận dạng. Ngôi sao ở phía trước nói "mở rộng danh sách". Có thể đọc được càng nhiều *lst, last = some_iterable. - pepr
@virtualxtc nope _ là biến đặc biệt trong python và được sử dụng để lưu trữ giá trị cuối cùng hoặc để nói rằng tôi không quan tâm đến giá trị để có thể được làm sạch. - DhiaTN


Điều này dường như không nhanh hơn vòng lặp trống vì lambda, nhưng có lẽ nó sẽ cho người khác ý tưởng

reduce(lambda x,y:y,my_iter)

Nếu vòng lặp trống, một TypeError được nâng lên


18
2018-01-26 11:59





Đơn giản như:

max(enumerate(the_iter))[1]

16
2018-06-06 11:24



Ồ, điều này là thông minh. Không phải là hiệu quả nhất hoặc dễ đọc, nhưng thông minh. - timgeb
Vì vậy, chỉ cần suy nghĩ to ... Điều này làm việc vì enumerate trả về (index, value) như: (0, val0), (1, val1), (2, val2)... và sau đó theo mặc định max khi đưa ra một danh sách các bộ dữ liệu, so sánh chỉ với giá trị đầu tiên của bộ tuple, trừ khi hai giá trị đầu tiên bằng nhau, chúng không bao giờ ở đây vì chúng biểu diễn các chỉ mục. Sau đó, chỉ số theo sau là vì max trả về toàn bộ (idx, value) tuple trong khi chúng tôi chỉ quan tâm đến value. Ý tưởng thú vị. - Taylor Edmiston


Có cái này

list( the_iter )[-1]

Nếu chiều dài của sự lặp lại thực sự là sử thi - quá lâu để hiện thực hóa danh sách sẽ làm cạn kiệt bộ nhớ - thì bạn thực sự cần phải suy nghĩ lại về thiết kế.


4
2018-01-26 11:42



Đây là giải pháp đơn giản nhất. - laike9m
Nhẹ nhàng hơn để sử dụng một tuple. - Christopher Smith
Rất không đồng ý với câu cuối cùng. Làm việc với các bộ dữ liệu rất lớn (có thể vượt quá giới hạn bộ nhớ nếu nạp cùng một lúc) là lý do chính để sử dụng một trình lặp thay vì một danh sách. - Paul
@Paul: một số hàm chỉ trả về một trình lặp. Đây là một cách ngắn gọn và dễ đọc để làm điều đó trong trường hợp đó (đối với các danh sách không sử thi). - serv-inc