2010-06-24 30 views
61

Hiện nay tôi đang làm điều này:Một lớp lót để kiểm tra xem một trình vòng lặp có tạo ra ít nhất một phần tử không?

try: 
    something = iterator.next() 
    # ... 
except StopIteration: 
    # ... 

Nhưng tôi muốn một biểu thức mà tôi có thể đặt bên trong một tuyên bố đơn giản if. Có bất kỳ thứ gì được tích hợp sẵn để mã này trông ít vụng về không?

any() trả về False nếu có thể lặp lại trống, nhưng nó sẽ có khả năng lặp qua tất cả các mục nếu không. Tôi chỉ cần nó để kiểm tra mục đầu tiên.


Có người hỏi tôi đang cố gắng làm gì. Tôi đã viết một hàm thực hiện truy vấn SQL và mang lại kết quả của nó. Thỉnh thoảng khi tôi gọi hàm này, tôi chỉ muốn biết liệu truy vấn có trả về bất cứ điều gì và đưa ra quyết định dựa trên điều đó hay không.

+1

Cũng là một vấn đề với mã số đó là bạn không thể gói nó vào một hàm, vì nó sẽ ăn phần tử đầu tiên. Câu hỏi hay. – andrewrk

+1

Trong trường hợp của tôi, tôi không cần yếu tố nào cả, tôi chỉ muốn biết có ít nhất một phần tử. –

+2

hah! Trường hợp sử dụng tương tự của tôi trong việc cố gắng tìm ra giải pháp tương tự! – Daniel

Trả lời

102

any sẽ không vượt quá phần tử đầu tiên nếu đó là True. Trong trường hợp trình vòng lặp sinh ra một cái gì đó sai-ish bạn có thể viết any(True for _ in iterator).

+0

Điều này có vẻ phù hợp với tôi, với re.finditer. Bạn có thể kiểm tra bất kỳ điểm dừng nào thành công đầu tiên một cách dễ dàng: chạy 'bất kỳ ((x> 100 cho x trong xrange (10000000)))' và sau đó chạy 'bất kỳ ((x> 10000000 cho x trong xrange (100000000)))' - - thứ hai sẽ mất nhiều thời gian hơn. – chbrown

+0

Điều này làm việc cho trường hợp "ít nhất x" 'tổng (1 cho _ trong itertools.islice (iterator, max_len))> = max_len' –

+8

Tương tự nếu bạn cần kiểm tra xem trình vòng lặp có trống không, người ta có thể sử dụng' tất cả (Sai cho _ trong iterator) 'sẽ kiểm tra nếu iterator là trống rỗng. (tất cả trả về True nếu trình vòng lặp trống, nếu không nó sẽ dừng khi nó thấy phần tử False đầu tiên) – KGardevoir

0

__length_hint__ước tính chiều dài của list(it) - đó là phương pháp tư nhân, mặc dù:

x = iter((1, 2, 3)) 
help(x.__length_hint__) 
     1 Help on built-in function __length_hint__: 
     2 
     3 __length_hint__(...) 
     4  Private method returning an estimate of len(list(it)). 
+3

không được đảm bảo cho mọi trình lặp. >>> def nó(): ... mang 1 ... mang 2 ... mang lại 3 ... >>> i = nó() >>> i .__ length_hint__ Traceback (cuộc gọi gần đây nhất): Tệp "", dòng 1, trong Thuộc tínhLỗi: đối tượng 'máy phát điện' không có thuộc tính '__length_hint__' – andrewrk

+3

Nó cũng có thể hợp pháp để trả về 0 cho một trình lặp có nhiều hơn 0 mục , vì nó chỉ là một gợi ý. –

18

Đây không phải là thực sự sạch hơn, nhưng nó cho thấy một cách để gói nó trong một hàm losslessly:

def has_elements(iter): 
    from itertools import tee 
    iter, any_check = tee(iter) 
    try: 
    any_check.next() 
    return True, iter 
    except StopIteration: 
    return False, iter 

has_el, iter = has_elements(iter) 
if has_el: 
    # not empty 

Đây không phải là thực sự pythonic, và đối với trường hợp cụ thể, có lẽ tốt hơn (nhưng ít chung) các giải pháp, như mặc định next.

first = next(iter, None) 
if first: 
    # Do something 

Đây không phải là chung vì Không có thể là yếu tố hợp lệ trong nhiều lần lặp lại.

+0

Đây có lẽ là cách tốt nhất để làm điều này. Tuy nhiên, nó sẽ giúp để biết những gì OP đang cố gắng để làm gì? Có lẽ có một giải pháp thanh lịch hơn (IS Python này, sau khi tất cả). – rossipedia

+0

Cảm ơn, tôi nghĩ tôi sẽ sử dụng 'next()'. –

+1

@Bastien, tốt, nhưng làm như vậy với một _sentinel_ thích hợp (xem câu trả lời của tôi). –

5

bạn có thể sử dụng:

if zip([None], iterator): 
    # ... 
else: 
    # ... 

nhưng đó là một chút nonexplanatory cho đầu đọc mã

+2

.. (bạn có thể sử dụng bất kỳ mục nào có thể lặp lại thay vì [Không có]) – mykhal

0

Đây là một wrapper iterator overkill mà thường cho phép để kiểm tra xem có một món đồ tiếp theo (thông qua chuyển đổi sang boolean) . Tất nhiên là không hiệu quả.

class LookaheadIterator(): 

    def __init__(self, iterator): 
     self.__iterator = iterator 
     try: 
      self.__next  = next (iterator) 
      self.__have_next = True 
     except StopIteration: 
      self.__have_next = False 

    def __iter__(self): 
     return self 

    def next (self): 
     if self.__have_next: 
      result = self.__next 
      try: 
       self.__next  = next (self.__iterator) 
       self.__have_next = True 
      except StopIteration: 
       self.__have_next = False 

      return result 

     else: 
      raise StopIteration 

    def __nonzero__(self): 
     return self.__have_next 

x = LookaheadIterator (iter ([])) 
print bool (x) 
print list (x) 

x = LookaheadIterator (iter ([1, 2, 3])) 
print bool (x) 
print list (x) 

Output:

False 
[] 
True 
[1, 2, 3] 
31

Trong Python 2.6+, nếu tên sentinel được ràng buộc với một giá trị mà iterator không thể nào mang lại,

if next(iterator, sentinel) is sentinel: 
    print('iterator was empty') 

Nếu bạn không có ý tưởng về những gì mà trình vòng lặp có thể có khả năng sinh lợi, hãy tạo mã thông báo của riêng bạn (ví dụ: ở đầu mô-đun của bạn) với

sentinel = object() 

Nếu không, bạn có thể sử dụng, trong vai trò sentinel, bất kỳ giá trị nào bạn "biết" (dựa trên các cân nhắc của ứng dụng) mà trình vòng lặp không thể mang lại.

0

Một chút muộn, nhưng ... Bạn có thể biến các iterator vào một danh sách và sau đó làm việc với danh sách đó:

# Create a list of objects but runs out the iterator. 
l = [_ for _ in iterator] 

# If the list is not empty then the iterator had elements; else it was empty. 
if l : 
    pass # Use the elements of the list (i.e. from the iterator) 
else : 
    pass # Iterator was empty, thus list is empty. 
+2

Điều này không hiệu quả vì nó liệt kê toàn bộ danh sách. Sẽ không làm việc cho các máy phát vô hạn. – becko

+0

@becko: Đồng ý. Nhưng đó không phải là trường hợp trong câu hỏi ban đầu. – Jens

+1

Một vấn đề khác là trình lặp có thể tạo ra một số lượng vô hạn các đối tượng có thể dẫn đến tràn bộ nhớ, và thực tế là chương trình sẽ không bao giờ đạt được câu lệnh tiếp theo –

1

gì về:

In [1]: i=iter([]) 

In [2]: bool(next(i,False)) 
Out[2]: False 

In [3]: i=iter([1]) 

In [4]: bool(next(i,False)) 
Out[4]: True 
+0

Thú vị nhất! Nhưng điều gì sẽ xảy ra nếu next() trả về False bởi vì nó thực sự mang lại lợi ích gì? –

Các vấn đề liên quan