Kiểm tra xem có thứ gì đó (không) trong danh sách trong Python không


314

Tôi có một danh sách các bộ dữ liệu trong Python và tôi có một điều kiện mà tôi muốn lấy nhánh CHỈ nếu bộ dữ liệu không có trong danh sách (nếu nó nằm trong danh sách, thì tôi không muốn lấy nhánh if)

if curr_x -1 > 0 and (curr_x-1 , curr_y) not in myList: 

    # Do Something

Điều này không thực sự làm việc cho tôi mặc dù. Tôi đã làm gì sai?


1
Lưu ý rằng 3 -1 > 0 and (4-1 , 5) not in []Truedo đó các lỗi không phải là một trong những ưu tiên điều hành.
Dan D.

6
Ý bạn là gì khi "không thực sự làm việc cho tôi"? Bạn mong đợi điều gì sẽ xảy ra? Điều gì thực sự xảy ra? Nội dung danh sách chính xác nào gây ra vấn đề?
Karl Knechtel

Tại sao không thử myList.count((curr_x, curr_y)), nếu (curr_x, curr_y)không có myList, kết quả sẽ là0
LittleLittleQ


2
Làm thế nào mà câu hỏi "mã của tôi không thực sự hiệu quả với tôi" nhận được 297 lượt upvote? Xin vui lòng cho chúng tôi một ví dụ tái sản xuất tối thiểu .
gerrit

Câu trả lời:


503

Lỗi có thể là một nơi khác trong mã của bạn, bởi vì nó sẽ hoạt động tốt:

>>> 3 not in [2, 3, 4]
False
>>> 3 not in [4, 5, 6]
True

Hoặc với bộ dữ liệu:

>>> (2, 3) not in [(2, 3), (5, 6), (9, 1)]
False
>>> (2, 3) not in [(2, 7), (7, 3), "hi"]
True

11
@Zack: nếu bạn không biết về điều này, bạn có thể làm điều đóif not ELEMENT in COLLECTION:
ninjagecko

@ninjagecko: tùy thuộc vào loại container có thể kém hiệu quả hơn, hoặc thậm chí không chính xác. Xem ví dụ bộ lọc nở .
orlp

14
@nightcracker Điều đó không có ý nghĩa gì khi A not in Bgiảm bớt việc làm not B.__contains__(A)giống như những gì not A in Bđược giảm xuống not B.__contains__(A).
Dan D.

1
Ôi chà, tôi đã có thể tuyên thệ Python có thứ gì đó như thế __notcontains__. Tôi xin lỗi, sau đó những gì tôi nói chỉ là nhảm nhí.
orlp

2
@ std''OrgnlDave Cách duy nhất có thể xảy ra là nếu notcó quyền ưu tiên cao hơn mức inkhông có. Hãy xem xét kết quả ast.dump(ast.parse("not A in B").body[0])mà kết quả trong "Expr(value=UnaryOp(op=Not(), operand=Compare(left=Name(id='A', ctx=Load()), ops=[In()], comparators=[Name(id='B', ctx=Load())])))"Nếu notđược nhóm chặt chẽ với A, người ta sẽ mong đợi kết quả sẽ "Expr(value=Compare(left=UnaryOp(op=Not(), operand=Name(id='A', ctx=Load())), ops=[In()], comparators=[Name(id='B', ctx=Load())]))"là phân tích cho "(not A) in B".
Dan D.

20

Làm cách nào để kiểm tra xem có thứ gì đó (không) trong danh sách trong Python không?

Giải pháp rẻ nhất và dễ đọc nhất là sử dụng intoán tử (hoặc trong trường hợp cụ thể của bạn, not in). Như đã đề cập trong tài liệu,

Các nhà khai thác innot inkiểm tra thành viên. x in sđánh giá Truenếu xlà một thành viên của s, và Falsenếu không. x not in strả về phủ định của x in s.

Ngoài ra,

Toán tử not inđược định nghĩa là có giá trị thực nghịch đảo của in.

y not in xlà logic giống như not y in x.

Đây là vài ví dụ:

'a' in [1, 2, 3]
# False

'c' in ['a', 'b', 'c']
# True

'a' not in [1, 2, 3]
# True

'c' not in ['a', 'b', 'c']
# False

Điều này cũng hoạt động với các bộ dữ liệu, vì các bộ dữ liệu có thể băm được (do hậu quả của thực tế là chúng cũng bất biến):

(1, 2) in [(3, 4), (1, 2)]
#  True

Nếu đối tượng trên RHS định nghĩa một __contains__()phương thức, insẽ gọi bên trong nó, như đã lưu ý trong đoạn cuối của phần So sánh của các tài liệu.

... innot in, được hỗ trợ bởi các loại có thể lặp lại hoặc thực hiện __contains__()phương thức. Ví dụ: bạn có thể (nhưng không nên) làm điều này:

[3, 2, 1].__contains__(1)
# True

inngắn mạch, vì vậy nếu phần tử của bạn ở đầu danh sách, hãy inđánh giá nhanh hơn:

lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst  # Expected to take longer time.

68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 µs ± 5.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Nếu bạn muốn làm nhiều hơn là chỉ kiểm tra xem một mục có trong danh sách hay không, có các tùy chọn:

  • list.indexcó thể được sử dụng để lấy chỉ mục của một mục. Nếu yếu tố đó không tồn tại, a ValueErrorđược nâng lên.
  • list.count có thể được sử dụng nếu bạn muốn đếm số lần xuất hiện.

Vấn đề XY: Bạn đã xem xét sets?

Hãy tự hỏi mình những câu hỏi sau:

  • Bạn có cần kiểm tra xem một mục có trong danh sách nhiều lần không?
  • Là kiểm tra này được thực hiện trong một vòng lặp, hoặc một chức năng được gọi nhiều lần?
  • Các mặt hàng bạn đang lưu trữ trong danh sách của bạn có thể băm không? IOW, bạn có thể gọi hashcho họ?

Nếu bạn trả lời "có" cho những câu hỏi này, bạn nên sử dụng setthay thế. Một inbài kiểm tra thành viên trên lists là độ phức tạp thời gian O (n). Điều này có nghĩa là python phải thực hiện quét tuyến tính danh sách của bạn, truy cập từng phần tử và so sánh nó với mục tìm kiếm. Nếu bạn đang làm điều này nhiều lần hoặc nếu danh sách lớn, thao tác này sẽ phải chịu chi phí.

setmặt khác, các đối tượng băm giá trị của chúng để kiểm tra tư cách thành viên liên tục. Kiểm tra cũng được thực hiện bằng cách sử dụng in:

1 in {1, 2, 3} 
# True

'a' not in {'a', 'b', 'c'}
# False

(1, 2) in {('a', 'c'), (1, 2)}
# True

Nếu bạn không may là phần tử bạn đang tìm kiếm / không tìm kiếm nằm ở cuối danh sách của bạn, python sẽ quét danh sách cho đến cuối. Điều này là hiển nhiên từ thời gian dưới đây:

l = list(range(100001))
s = set(l)

%timeit 100000 in l
%timeit 100000 in s

2.58 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Xin nhắc lại, đây là một tùy chọn phù hợp miễn là các yếu tố bạn lưu trữ và tìm kiếm có thể băm được. IOW, chúng sẽ phải là các loại bất biến, hoặc các đối tượng thực hiện __hash__.


2
Các bộ không phải luôn luôn là một tùy chọn (ví dụ: khi có danh sách các mục có thể thay đổi). Đối với các bộ sưu tập lớn: việc xây dựng bộ tìm kiếm là thời gian O (n) và có thể tăng gấp đôi mức sử dụng bộ nhớ của bạn. Nếu bạn chưa có một cái nhìn xung quanh, nó không phải luôn luôn là lựa chọn tốt nhất để thực hiện / duy trì.
wim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.