ตรวจสอบว่ามีบางสิ่ง (ไม่) ในรายการใน Python


314

ฉันมีรายการ tuples ในPythonและมีเงื่อนไขที่ฉันต้องการนำสาขาเท่านั้นหาก tuple ไม่อยู่ในรายการ (ถ้าอยู่ในรายการจากนั้นฉันไม่ต้องการใช้สาขาถ้า)

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

    # Do Something

แม้ว่ามันจะไม่ได้ผลสำหรับฉัน ฉันทำอะไรผิด


1
โปรดทราบว่า3 -1 > 0 and (4-1 , 5) not in []Trueข้อผิดพลาดไม่ใช่หนึ่งในตัวดำเนินการที่สำคัญ
Dan D.

6
คุณหมายความว่าอย่างไร "ไม่ได้ผลสำหรับฉัน" คุณคาดหวังว่าจะเกิดอะไรขึ้น เกิดอะไรขึ้นจริงหรือ เนื้อหารายการที่แน่นอนใดที่ทำให้เกิดปัญหา
Karl Knechtel

ทำไมไม่ลองmyList.count((curr_x, curr_y))ถ้า(curr_x, curr_y)ไม่ได้myListผลลัพธ์จะเป็น0
LittleLittleQ


2
คำถาม "รหัสของฉันใช้งานไม่ได้กับฉันจริง ๆ " ได้รับ 297 upvotes อย่างไร โปรดให้เราตัวอย่างเช่นสามารถทำซ้ำได้น้อยที่สุด
gerrit

คำตอบ:


502

ข้อผิดพลาดน่าจะเป็นที่อื่นในรหัสของคุณเพราะมันควรจะทำงานได้ดี:

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

หรือด้วยสิ่งอันดับ:

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

11
@ แซค: ถ้าคุณไม่รู้เรื่องนี้คุณก็ทำได้if not ELEMENT in COLLECTION:
ninjagecko

@ninjagecko: ขึ้นอยู่กับประเภทของคอนเทนเนอร์ที่อาจมีประสิทธิภาพน้อยลงหรือไม่ถูกต้อง ดูตัวอย่างฟิลเตอร์บาน
orlp

14
@nightcracker ที่ทำให้รู้สึกไม่เป็นA not in Bจะลดลงไปทำnot B.__contains__(A)ซึ่งเป็นเช่นเดียวกับสิ่งที่จะลดลงไปซึ่งเป็นnot A in B not B.__contains__(A)
Dan D.

1
โอ้ว้าวฉันสาบานได้เลยว่า Python มีบางอย่างที่เหมือน__notcontains__กัน ฉันขอโทษแล้วสิ่งที่ฉันพูดก็แค่พล่าม
orlp

2
@ std''OrgnlDave วิธีเดียวที่อาจเกิดขึ้นได้คือหากnotมีลำดับความสำคัญสูงกว่าinที่ไม่ได้เป็น พิจารณาผลจากการast.dump(ast.parse("not A in B").body[0])ที่ส่งผลให้"Expr(value=UnaryOp(op=Not(), operand=Compare(left=Name(id='A', ctx=Load()), ops=[In()], comparators=[Name(id='B', ctx=Load())])))"หากnotจัดกลุ่มแน่นหนึ่งคาดว่าจะมีผลที่จะเป็นซึ่งเป็นแยกสำหรับ"Expr(value=Compare(left=UnaryOp(op=Not(), operand=Name(id='A', ctx=Load())), ops=[In()], comparators=[Name(id='B', ctx=Load())]))" "(not A) in B"
Dan D.

20

ฉันจะตรวจสอบว่ามีสิ่งใด (ไม่) ในรายการใน Python ได้อย่างไร

วิธีที่ถูกที่สุดและอ่านง่ายที่สุดคือการใช้inโอเปอเรเตอร์ (หรือในกรณีเฉพาะของคุณnot in) ตามที่ระบุไว้ในเอกสาร

ผู้ประกอบการinและnot inทดสอบการเป็นสมาชิก x in sประเมิน Trueว่าหากxเป็นสมาชิกของsและFalseอื่น ๆ ผลตอบแทนของการปฏิเสธx not in sx in s

นอกจากนี้

ผู้ประกอบการที่มีการกำหนดให้มีมูลค่าที่แท้จริงผกผันของnot inin

y not in xnot y in xเป็นเหตุผลเดียวกับ

นี่คือตัวอย่างบางส่วน:

'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

สิ่งนี้ยังทำงานร่วมกับสิ่งอันดับเนื่องจากสิ่งอันดับเป็น hashable (อันเป็นผลมาจากความจริงที่ว่าพวกมันยังไม่เปลี่ยนรูป):

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

หากวัตถุบน RHS กำหนด__contains__()วิธีการinภายในจะเรียกมันดังที่ระบุไว้ในวรรคสุดท้ายของส่วนการเปรียบเทียบของเอกสาร

... inและnot inได้รับการสนับสนุนตามประเภทที่ iterable หรือใช้ __contains__()วิธีการ ตัวอย่างเช่นคุณสามารถ (แต่ไม่ควร) ทำสิ่งนี้:

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

inลัดวงจรดังนั้นหากองค์ประกอบของคุณอยู่ที่จุดเริ่มต้นของรายการinประเมินได้เร็วขึ้น:

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)

หากคุณต้องการทำมากกว่าเพียงแค่ตรวจสอบว่ารายการนั้นอยู่ในรายการหรือไม่มีตัวเลือกดังนี้:

  • list.indexสามารถใช้เพื่อดึงดัชนีของรายการ หากองค์ประกอบนั้นไม่มีอยู่ValueErrorก็จะถูกยกขึ้น
  • list.count สามารถใช้หากคุณต้องการนับการเกิดขึ้น

ปัญหา XY: คุณเคยคิดsetหรือไม่

ถามตัวเองด้วยคำถามเหล่านี้:

  • คุณจำเป็นต้องตรวจสอบว่ารายการนั้นอยู่ในรายการมากกว่าหนึ่งครั้งหรือไม่
  • การตรวจสอบนี้เสร็จสิ้นภายในลูปหรือฟังก์ชั่นที่เรียกซ้ำ ๆ กันหรือไม่?
  • รายการที่คุณจัดเก็บในรายการของคุณแฮชได้หรือไม่? IOW คุณโทรหาhashพวกเขาได้ไหม?

หากคุณตอบคำถามเหล่านี้ว่า "ใช่" คุณควรใช้setแทน การinทดสอบการเป็นสมาชิกlistของ s คือความซับซ้อนของเวลา O (n) ซึ่งหมายความว่าหลามจะต้องทำการสแกนเชิงเส้นของรายการของคุณเยี่ยมชมแต่ละองค์ประกอบและเปรียบเทียบกับรายการค้นหา หากคุณทำเช่นนี้ซ้ำ ๆ หรือถ้ารายการมีขนาดใหญ่การดำเนินการนี้จะเกิดค่าใช้จ่าย

setวัตถุในทางกลับกันแฮชค่าสำหรับการตรวจสอบสมาชิกคงที่ การตรวจสอบทำได้โดยใช้in:

1 in {1, 2, 3} 
# True

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

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

หากคุณโชคร้ายพอที่องค์ประกอบที่คุณกำลังค้นหา / ไม่ค้นหาอยู่ท้ายรายการของคุณหลามจะทำการสแกนรายการจนจบ เรื่องนี้เห็นได้ชัดจากการกำหนดเวลาด้านล่าง:

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)

เพื่อเป็นการเตือนความจำนี่เป็นตัวเลือกที่เหมาะสมตราบใดที่องค์ประกอบที่คุณจัดเก็บและมองดูนั้นมีแฮช IOW, __hash__พวกเขาทั้งสองจะต้องเป็นชนิดที่ไม่เปลี่ยนรูปหรือวัตถุที่ใช้


2
ชุดไม่ใช่ตัวเลือกเสมอ (ตัวอย่างเช่นเมื่อมีรายการของรายการที่ไม่แน่นอน) สำหรับคอลเลกชันขนาดใหญ่: การสร้างชุดสำหรับการค้นหาคือเวลาO (n)ต่อไปและสามารถเพิ่มการใช้หน่วยความจำของคุณเป็นสองเท่า หากคุณยังไม่มีการค้นหารอบ ๆ มันไม่ใช่ตัวเลือกที่ดีที่สุดในการสร้าง / ดูแลรักษา
Wim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.