2012-05-19 16 views
97

Tôi có một danh sách gồm 20000 danh sách. Tôi sử dụng phần tử thứ 3 của mỗi danh sách làm cờ. Tôi muốn thực hiện một số thao tác trên danh sách này miễn là ít nhất một phần tử của cờ là 0, giống như:Làm cách nào để kiểm tra xem tất cả các thành phần của danh sách có phù hợp với điều kiện không?

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....] 

Ban đầu tất cả cờ là 0. Tôi sử dụng vòng lặp while để kiểm tra xem có ít nhất một phần tử không cờ là 0:

def check(lista): 
    for item in lista: 
     if item[2] == 0: 
      return True 
    return False 

Nếu check(my_list) lợi nhuận True, sau đó tôi tiếp tục làm việc trên danh sách của tôi:

while check(my_list): 
    for item in my_list: 
     if condition: 
      item[2] = 1 
     else: 
      do_sth() 

Thật sự tôi muốn loại bỏ yếu tố trong my_list như tôi lặp vượt qua nó, nhưng tôi không được phép xóa mục khi tôi lặp lại nó.

gốc my_list không có cờ:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....] 

Vì tôi không thể loại bỏ yếu tố như tôi lặp qua nó, tôi phát minh ra những lá cờ. Nhưng my_list chứa nhiều mục và vòng lặp while đọc tất cả các mục đó tại mỗi vòng for và nó tiêu tốn rất nhiều thời gian! Bạn có đề nghị nào không?

+2

Hình như cấu trúc dữ liệu của bạn không phải là lý tưởng cho các vấn đề của bạn.Nếu bạn giải thích ngữ cảnh nhiều hơn một chút, có lẽ chúng ta có thể gợi ý điều gì đó thích hợp hơn. – uselpa

+0

Có thể bạn có thể thay thế các mục bằng 'None' hoặc' [] 'khi bạn lặp qua danh sách thay vì xóa chúng. Kiểm tra toàn bộ danh sách với 'check() 'lặp qua tất cả các mục trước mỗi pass trên vòng lặp bên trong là một cách tiếp cận rất chậm. – martineau

Trả lời

211

Câu trả lời hay nhất ở đây là sử dụng all(), là nội dung dựng sẵn cho tình huống này. Chúng tôi kết hợp điều này với một số generator expression để tạo ra kết quả bạn muốn một cách sạch sẽ và hiệu quả. Ví dụ:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]] 
>>> all(item[2] == 0 for item in items) 
True 
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]] 
>>> all(item[2] == 0 for item in items) 
False 

Và, ví dụ bộ lọc của mình, một danh sách hiểu:

>>> [x for x in items if x[2] == 0] 
[[1, 2, 0], [1, 2, 0]] 

Nếu bạn muốn kiểm tra ít nhất một phần tử là 0, lựa chọn tốt hơn là sử dụng any() mà là nhiều hơn có thể đọc được:

>>> any(item[2] == 0 for item in items) 
True 
+0

Lỗi của tôi về việc sử dụng lambda, tất cả Python không chấp nhận một hàm làm đối số đầu tiên như Haskell et. al., Tôi cũng đã thay đổi câu trả lời của mình thành một danh sách hiểu. :) –

+2

@HampusNilsson Việc hiểu danh sách không giống như biểu thức trình tạo. Ví dụ, khi 'all()' và 'any()' ngắn mạch, giá trị đầu tiên của tôi đánh giá thành 'False',' all() 'sẽ thất bại và không kiểm tra thêm bất kỳ giá trị nào, trả về' False'. Ví dụ của bạn sẽ làm tương tự, ngoại trừ nó sẽ tạo ra toàn bộ danh sách so sánh trước, có nghĩa là rất nhiều xử lý không có gì. –

5

Bạn có thể sử dụng itertools's takewhile như thế này, nó sẽ dừng lại khi điều kiện được đáp ứng không thành công câu lệnh của bạn. Phương pháp ngược lại sẽ là dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list) 
    print x 
3

Nếu bạn muốn kiểm tra xem bất kỳ mục nào trong danh sách vi phạm việc sử dụng điều kiện all:

if all([x[2] == 0 for x in lista]): 
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary) 

Để loại bỏ tất cả các yếu tố không phù hợp, sử dụng filter

# Will remove all elements where x[2] is 0 
listb = filter(lambda x: x[2] != 0, listb) 
0

cách này là linh hoạt hơn một chút so với sử dụng all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]] 
all_zeros = False if False in [x[2] == 0 for x in my_list] else True 
any_zeros = True if True in [x[2] == 0 for x in my_list] else False 
0

Một cách khác để sử dụng itertools.ifilter. Này kiểm tra và xử lý truthiness (sử dụng lambda)

Sample-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list): 
    print x 
Các vấn đề liên quan