จะตรวจสอบว่าหนึ่งในรายการต่อไปนี้อยู่ในรายการได้อย่างไร?


220

ฉันกำลังพยายามหาวิธีสั้น ๆ เพื่อดูว่ามีรายการใดต่อไปนี้อยู่ในรายการหรือไม่ แต่ความพยายามครั้งแรกของฉันไม่ทำงาน นอกเหนือจากการเขียนฟังก์ชั่นเพื่อทำให้สิ่งนี้สำเร็จแล้วเป็นวิธีที่สั้น ๆ ในการตรวจสอบว่าหนึ่งในหลาย ๆ รายการอยู่ในรายการหรือไม่

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

สิ่งที่ตลกฉันตรวจสอบว่า 'และ' พฤติกรรม a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] print( (1 and 2) in b ,(2 and 1) in b ,(1 and 2) in c ,(2 and 1) in c, sep='\n')เป็นจริงเท็จเท็จจริง
Piotr Kamoda

คำตอบ:


266
>>> L1 = [2,3,4]
>>> L2 = [1,2]
>>> [i for i in L1 if i in L2]
[2]


>>> S1 = set(L1)
>>> S2 = set(L2)
>>> S1.intersection(S2)
set([2])

ทั้งรายการว่างและชุดว่างเป็นเท็จดังนั้นคุณสามารถใช้ค่าโดยตรงเป็นค่าความจริง


6
แนวคิดการแยกให้แนวคิดนี้กับฉัน return len (set (a) .interection (set (b)))
Deon

14
FWIW - ฉันทำการเปรียบเทียบความเร็วและทางออกแรกที่เสนอที่นี่คือการอดอาหาร
jackiekazil

2
@ user89788 คำตอบของการใช้ตัวกำเนิดไฟฟ้านั้นเร็วขึ้นอีกมากเพราะanyสามารถคืนค่าได้เร็วที่สุดเมื่อพบTrueค่า - ไม่ต้องสร้างรายชื่อทั้งหมดก่อน
Anentropic

โซลูชันที่สอง / ชุดจะไม่ทำงานหากคุณทำซ้ำในรายการ (ตามที่ชุดมีเพียงหนึ่งในแต่ละรายการ) ถ้า `L1 = [1,1,2,3] 'และ' L2 = [1,2,3] 'รายการทั้งหมดจะถูกตัดกัน
donrondadon

ฉันรู้ว่านี่เกือบ 10 ปีแล้ว แต่ทางออกแรกดูเหมือนจะไม่เหมาะกับฉัน ฉันได้แทนที่ตัวเลขใน L2 สำหรับสตริงและฉันได้รับข้อผิดพลาดต่อไปนี้: TypeError: 'ใน <string>' ต้องการสตริงเป็นตัวถูกดำเนินการด้านซ้ายไม่ใช่รายการ
roastbeeef

227

โทเบียสคุณเอาชนะฉันให้ได้ ฉันกำลังคิดถึงการเปลี่ยนแปลงเล็กน้อยในโซลูชันของคุณ:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True

5
ฉันรู้ว่านี่เป็นคำตอบที่เก่ามาก แต่ถ้ารายการหนึ่งยาวมากและอีกสั้น ๆ มีคำสั่งที่จะให้ประสิทธิภาพเร็วขึ้นหรือไม่ (เช่นx in long for x in shortvs x in short for x in long)
Luke Sapan

11
@LukeSapan: คุณถูกต้อง คำสั่งนั้นสามารถรับได้ผ่าน "พิมพ์ใด ๆ (x ในสูงสุด (a, b, key = len) สำหรับ x ในนาที (a, b, key = len))" นี่ใช้ x ยาวสำหรับ x ในระยะสั้น
Nuclearman

2
นี่คือคำตอบที่ดีที่สุดเพราะมันใช้เครื่องกำเนิดไฟฟ้าและจะกลับมาทันทีที่พบการแข่งขัน (อย่างที่คนอื่นพูดไม่ใช่แค่คำตอบนี้!)
คอม

4
@ นิวเคลียสระวัง: หากทั้งสองรายการaและbมีความยาวเท่ากันสูงสุดและต่ำสุดจะส่งกลับรายการซ้ายสุดซึ่งทำให้การany()โทรดำเนินการผ่านรายการเดียวกันทั้งสองด้าน any(x in max(a, b, key=len) for x in (b, a, key=len))ถ้าคุณอย่างต้องมีการตรวจสอบความยาวกลับคำสั่งของรายการในสายที่สองนี้:
โนอาห์โบการ์ต

3
@NoahBogart คุณถูกต้องและวิธีการแก้ปัญหาที่ดูเหมือนว่าดีใด ๆ ฉันยังคิดว่าคุณหมายถึง: any(x in max(a, b, key=len) for x in min(b, a, key=len))(พลาดนาที)
Nuclearman

29

อาจจะขี้เกียจนิดหน่อย:

a = [1,2,3,4]
b = [2,7]

print any((True for x in a if x in b))

1
มันเกือบจะเหมือนกับที่ฉันโพสต์
Bastien Léonard

5
@ BastienLéonard ... ยกเว้นมันเร็วกว่ามากเพราะใช้ตัวกำเนิดไฟฟ้าและanyสามารถกลับมาเร็วได้ในขณะที่รุ่นของคุณต้องสร้างรายการทั้งหมดจากความเข้าใจก่อนanyจึงจะสามารถใช้งานได้ คำตอบของ @ user89788 ดีกว่าเล็กน้อยเพราะวงเล็บคู่ไม่จำเป็น
Anentropic

17

ลองนึกถึงสิ่งที่รหัสพูดจริง ๆ !

>>> (1 or 2)
1
>>> (2 or 1)
2

นั่นอาจจะอธิบายได้ :) Python ใช้ "ขี้เกียจหรือ" อย่างเห็นได้ชัดซึ่งไม่น่าแปลกใจเลย มันทำอะไรแบบนี้:

def or(x, y):
    if x: return x
    if y: return y
    return False

ในตัวอย่างแรกและx == 1 y == 2ในตัวอย่างที่สองมันกลับกัน นั่นเป็นเหตุผลที่มันส่งกลับค่าที่แตกต่างกันขึ้นอยู่กับลำดับของพวกเขา


16
a = {2,3,4}
if {1,2} & a:
    pass

รุ่นรหัสกอล์ฟ พิจารณาใช้ชุดถ้ามันเหมาะสมที่จะทำ ฉันพบว่าสิ่งนี้สามารถอ่านได้มากกว่าความเข้าใจในรายการ


12

1 บรรทัดโดยไม่มีความเข้าใจในรายการ

>>> any(map(lambda each: each in [2,3,4], [1,2]))
True
>>> any(map(lambda each: each in [2,3,4], [1,5]))
False
>>> any(map(lambda each: each in [2,3,4], [2,4]))
True


6

ใน python 3 เราสามารถเริ่มต้นใช้เครื่องหมายดอกจันได้ รับสองรายการ:

bool(len({*a} & {*b}))

แก้ไข: รวมข้อเสนอแนะของ alkanen


1
@Anony จะสร้างชุดที่มีองค์ประกอบใน a และอีกชุดที่มีองค์ประกอบใน b จากนั้นจะพบจุดตัด (องค์ประกอบที่ใช้ร่วมกัน) ระหว่างชุดเหล่านั้นกับชุดใด ๆ () จะคืนค่าจริงหากมีองค์ประกอบดังกล่าวที่เป็นความจริง วิธีแก้ปัญหาจะไม่ทำงานหากองค์ประกอบที่ใช้ร่วมกันเพียงอย่างเดียวเป็นเท็จ (เช่นหมายเลข 0) มันอาจจะดีกว่าที่จะใช้ len () มากกว่าใด ๆ ()
alkanen

1
@alkanen การโทรที่ดี
Daniel Braun

ทำไมไม่ใช้ฟังก์ชั่นการตั้งค่า?
Alex78191

5

เมื่อคุณคิดว่า "ตรวจสอบเพื่อดูว่า a ในข" ให้คิดแฮช (ในกรณีนี้คือชุด) วิธีที่เร็วที่สุดคือการแฮชรายการที่คุณต้องการตรวจสอบแล้วตรวจสอบแต่ละรายการในนั้น

นี่คือสาเหตุที่คำตอบของ Joe Koberg รวดเร็ว: การตรวจสอบจุดตัดชุดนั้นเร็วมาก

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

tocheck = [1,2] # items to check
a = [2,3,4] # the list

a = set(a) # convert to set (O(len(a)))
print [i for i in tocheck if i in a] # check items (O(len(tocheck)))

เมื่อจำนวนรายการที่คุณต้องการตรวจสอบมีขนาดเล็กความแตกต่างอาจเล็กน้อย แต่ตรวจสอบตัวเลขจำนวนมากกับรายการที่มีขนาดใหญ่ ...

การทดสอบ:

from timeit import timeit

methods = ['''tocheck = [1,2] # items to check
a = [2,3,4] # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = [2,3,4]
L2 = [1,2]
[i for i in L1 if i in L2]''',

'''S1 = set([2,3,4])
S2 = set([1,2])
S1.intersection(S2)''',

'''a = [1,2]
b = [2,3,4]
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=10000)

print

methods = ['''tocheck = range(200,300) # items to check
a = range(2, 10000) # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = range(2, 10000)
L2 = range(200,300)
[i for i in L1 if i in L2]''',

'''S1 = set(range(2, 10000))
S2 = set(range(200,300))
S1.intersection(S2)''',

'''a = range(200,300)
b = range(2, 10000)
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=1000)

ความเร็ว:

M1: 0.0170331001282 # make one set
M2: 0.0164539813995 # list comprehension
M3: 0.0286040306091 # set intersection
M4: 0.0305438041687 # any

M1: 0.49850320816 # make one set
M2: 25.2735087872 # list comprehension
M3: 0.466138124466 # set intersection
M4: 0.668627977371 # any

วิธีการที่รวดเร็วอย่างต่อเนื่องคือการสร้างหนึ่งชุด (ของรายการ) แต่จุดตัดทำงานบนชุดข้อมูลขนาดใหญ่ที่ดีที่สุด!


3

ในบางกรณี (เช่นองค์ประกอบรายการที่ไม่ซ้ำกัน) สามารถใช้การดำเนินการแบบกำหนดได้

>>> a=[2,3,4]
>>> set(a) - set([2,3]) != set(a)
True
>>> 

หรือใช้set.isdisjoint () ,

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 

2

สิ่งนี้จะทำในหนึ่งบรรทัด

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True

ฉันไม่ได้รับจริงที่นี่ >>> พิมพ์ [2, 3, 4] >>> พิมพ์ b [2, 7] >>> ลด (lambda x, y: x ใน b, a) False
Deon

อ๋อ คุณถูก. ลด () ไม่ได้ค่อนข้างจัดการค่าบูลีนอย่างที่ฉันคิดว่ามันจะ ฉบับแก้ไขที่ฉันเขียนไว้ด้านบนใช้ได้กับกรณีนั้น
Chris Upchurch

2

ฉันรวบรวมวิธีแก้ไขปัญหาต่าง ๆ ที่กล่าวถึงในคำตอบอื่น ๆ และในความคิดเห็นจากนั้นทำการทดสอบความเร็ว เปิดออกเป็นที่เร็วที่สุดก็ยังไม่ได้ชะลอตัวลงมากเมื่อผลที่ได้not set(a).isdisjoint(b)False

ทั้งสามวิ่งทดสอบตัวอย่างเล็ก ๆ ของการกำหนดค่าที่เป็นไปได้ของและa bเวลามีหน่วยเป็นไมโครวินาที

Any with generator and max
        2.093 1.997 7.879
Any with generator
        0.907 0.692 2.337
Any with list
        1.294 1.452 2.137
True in list
        1.219 1.348 2.148
Set with &
        1.364 1.749 1.412
Set intersection explcit set(b)
        1.424 1.787 1.517
Set intersection implicit set(b)
        0.964 1.298 0.976
Set isdisjoint explicit set(b)
        1.062 1.094 1.241
Set isdisjoint implicit set(b)
        0.622 0.621 0.753

import timeit

def printtimes(t):
    print '{:.3f}'.format(t/10.0),

setup1 = 'a = range(10); b = range(9,15)'
setup2 = 'a = range(10); b = range(10)'
setup3 = 'a = range(10); b = range(10,20)'

print 'Any with generator and max\n\t',
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
print

print 'Any with generator\n\t',
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
print

print 'Any with list\n\t',
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
print

print 'True in list\n\t',
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
print

print 'Set with &\n\t',
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
print

print 'Set intersection explcit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
print

print 'Set intersection implicit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint explicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint implicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
print

0

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

ฉันลองทั้ง set () และ method ใด ๆ () แต่ยังมีปัญหาเรื่องความเร็ว ดังนั้นฉันจึงจำได้ว่า Raymond Hettinger กล่าวว่าทุกอย่างในไพ ธ อนเป็นพจนานุกรมและใช้ dict ทุกครั้งที่คุณทำได้ นั่นคือสิ่งที่ฉันพยายาม

ฉันใช้ defaultdict กับ int เพื่อระบุผลลัพธ์เชิงลบและใช้รายการในรายการแรกเป็นคีย์สำหรับรายการที่สอง (แปลงเป็น defaultdict) เนื่องจากคุณมีการค้นหาแบบ dict ทันทีคุณจึงรู้ได้ทันทีว่ามีรายการนั้นอยู่ใน defaultdict หรือไม่ ฉันรู้ว่าคุณไม่ได้เปลี่ยนโครงสร้างข้อมูลสำหรับรายการที่สองของคุณเสมอไป แต่ถ้าคุณสามารถทำได้ตั้งแต่เริ่มต้นมันก็จะเร็วขึ้นมาก คุณอาจต้องแปลง list2 (รายการที่ใหญ่ขึ้น) เป็น defaultdict โดยที่ key คือค่าที่เป็นไปได้ที่คุณต้องการตรวจสอบจากรายการเล็ก ๆ และค่าคือ 1 (hit) หรือ 0 (ไม่มี hit, default)

from collections import defaultdict
already_indexed = defaultdict(int)

def check_exist(small_list, default_list):
    for item in small_list:
        if default_list[item] == 1:
            return True
    return False

if check_exist(small_list, already_indexed):
    continue
else:
    for x in small_list:
        already_indexed[x] = 1

-4

ง่าย

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass

1
นี่ไม่ได้ตอบคำถาม OP ต้องการทราบว่ามีค่าใดจากรายการ aอยู่ในรายการbหรือไม่
That1Guy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.