Làm thế nào để kiểm tra nếu một trong các mục sau đây có trong danh sách không?


220

Tôi đang cố gắng tìm một cách ngắn để xem liệu có bất kỳ mục nào sau đây có trong danh sách không, nhưng lần thử đầu tiên của tôi không hoạt động. Bên cạnh việc viết một hàm để thực hiện điều này, là bất kỳ cách ngắn nào để kiểm tra xem một trong nhiều mục có trong danh sách hay không.

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

Điều thú vị là, tôi đã kiểm tra cách 'và' cư xử. 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')là Đúng Sai Sai Đúng
Piotr Kamoda

Câu trả lời:


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])

Cả danh sách trống và bộ trống đều là Sai, vì vậy bạn có thể sử dụng giá trị trực tiếp làm giá trị thật.


6
Ý tưởng giao nhau đã cho tôi ý tưởng này. return len (set (a) .intersection (set (b)))
Deon

13
FWIW - Tôi đã làm một so sánh tốc độ, và giải pháp đầu tiên được đưa ra ở đây là nhịn ăn cho đến nay.
jackiekazil

2
Câu trả lời của @ user89788 khi sử dụng trình tạo lại nhanh hơn nhiều, vì anycó thể quay lại sớm ngay khi tìm thấyTrue giá trị - trước tiên không phải xây dựng toàn bộ danh sách
Anentropic

Giải pháp thứ hai / bộ sẽ không hoạt động nếu bạn có các bản sao trong danh sách (vì các bộ chỉ chứa một trong mỗi mục). Nếu `L1 = [1,1,2,3] 'và' L2 = [1,2,3] ', tất cả các mục sẽ được nhìn thấy giao nhau.
donrondadon

Tôi biết điều này đã gần 10 tuổi, nhưng giải pháp đầu tiên dường như không hiệu quả với tôi. Tôi đã thay thế các số trong L2 cho các chuỗi và tôi đang gặp phải lỗi sau: TypeError: 'in <string>' yêu cầu chuỗi là toán hạng trái, không liệt kê
roastbeeef

227

Ah, Tobias bạn đánh tôi với nó. Tôi đã nghĩ về sự thay đổi nhỏ này trên giải pháp của bạn:

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

5
Tôi nhận ra đây là một câu trả lời rất cũ, nhưng nếu một danh sách rất dài và danh sách kia ngắn, liệu có một trật tự nào mang lại hiệu suất nhanh hơn không? (tức là x in long for x in shortso với x in short for x in long)
Luke Sapan

11
@LukeSapan: Bạn đúng rồi. Thứ tự đó có thể đạt được thông qua "in bất kỳ (x in max (a, b, key = len) cho x tính bằng min (a, b, key = len))". Điều này sử dụng x dài cho x ngắn.
Hạt nhân

2
Đây là câu trả lời tốt nhất vì nó sử dụng một trình tạo và sẽ quay lại ngay khi tìm thấy kết quả khớp (như những người khác đã nói, chỉ là không có câu trả lời này!).
dotcomly

4
@Nuclearman, xem ra: Nếu hai danh sách ablà cùng độ dài, max và min sẽ trở lại với trái nhất danh sách, mà làm cho any()cuộc gọi hoạt động trên cùng một danh sách của cả hai bên. Nếu bạn hoàn toàn yêu cầu kiểm tra độ dài, hãy đảo ngược thứ tự của danh sách trong cuộc gọi thứ hai : any(x in max(a, b, key=len) for x in (b, a, key=len)).

3
@NoahBogart Bạn đúng và giải pháp đó có vẻ tốt như bất kỳ. Tôi cũng cho rằng bạn có nghĩa là: any(x in max(a, b, key=len) for x in min(b, a, key=len))(bỏ lỡ phút).
Hạt nhân

29

Có lẽ lười hơn một chút:

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

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

1
Nó gần giống như bài tôi đã đăng.
Bastien Léonard

5
@ BastienLéonard ... ngoại trừ nó nhanh hơn nhiều vì nó sử dụng trình tạo và do đó anycó thể quay lại sớm, trong khi phiên bản của bạn phải xây dựng toàn bộ danh sách từ hiểu biết trước khi anycó thể sử dụng nó. Câu trả lời của @ user89788 tốt hơn một chút vì dấu ngoặc kép là không cần thiết
Anentropic

17

Hãy suy nghĩ về những gì mã thực sự nói!

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

Điều đó có lẽ nên giải thích nó. :) Python rõ ràng thực hiện "lười hoặc", điều này sẽ không gây ngạc nhiên. Nó thực hiện nó một cái gì đó như thế này:

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

Trong ví dụ đầu tiên, x == 1y == 2. Trong ví dụ thứ hai, nó ngược lại. Đó là lý do tại sao nó trả về các giá trị khác nhau tùy thuộc vào thứ tự của chúng.


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

Mã phiên bản golf. Cân nhắc sử dụng một bộ nếu nó có ý nghĩa để làm như vậy. Tôi thấy điều này dễ đọc hơn một sự hiểu biết danh sách.


12

1 dòng không có danh sách hiểu.

>>> 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

Trong python 3, chúng ta có thể bắt đầu sử dụng dấu hoa thị. Đưa ra hai danh sách:

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

Chỉnh sửa: kết hợp đề xuất của alkanen


1
@Anthony, nó tạo ra một tập hợp chứa các phần tử trong a và một tập hợp khác chứa các phần tử trong b, sau đó nó tìm giao điểm (các phần tử được chia sẻ) giữa các tập hợp đó và bất kỳ () nào trả về true nếu có bất kỳ phần tử nào như vậy là đúng. Giải pháp sẽ không hoạt động nếu (các) phần tử được chia sẻ duy nhất là giả mạo (chẳng hạn như số 0). Có thể sử dụng len () tốt hơn bất kỳ ()
alkanen

1
@alkanen Cuộc gọi tốt
Daniel Braun

Tại sao không sử dụng chức năng thiết lập?
Alex78191

5

Khi bạn nghĩ "kiểm tra xem nếu a trong b", hãy nghĩ băm (trong trường hợp này là bộ). Cách nhanh nhất là băm danh sách bạn muốn kiểm tra, sau đó kiểm tra từng mục trong đó.

Đây là lý do tại sao câu trả lời của Joe Koberg rất nhanh: kiểm tra giao lộ tập hợp rất nhanh.

Khi bạn không có nhiều dữ liệu, việc tạo các bộ có thể gây lãng phí thời gian. Vì vậy, bạn có thể tạo một bộ danh sách và chỉ cần kiểm tra từng mục:

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)))

Khi số lượng mặt hàng bạn muốn kiểm tra là nhỏ, sự khác biệt có thể không đáng kể. Nhưng hãy kiểm tra nhiều số với một danh sách lớn ...

kiểm tra:

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)

tốc độ:

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

Phương pháp luôn nhanh là tạo một bộ (trong danh sách), nhưng giao điểm hoạt động trên các tập dữ liệu lớn là tốt nhất!


3

Trong một số trường hợp (ví dụ: các thành phần danh sách duy nhất), có thể sử dụng các thao tác thiết lập.

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

Hoặc, bằng cách sử dụng set.itorisjoint () ,

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

2

Điều này sẽ làm điều đó trong một dòng.

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

Tôi không nhận được một Đúng đây >>> in [2, 3, 4] >>> print b [2, 7] >>> giảm (lambda x, y: x trong b, a) Sai
Deon

Vâng. Bạn đúng. giảm () không hoàn toàn xử lý các giá trị boolean theo cách tôi nghĩ nó sẽ. Phiên bản sửa đổi tôi đã viết ở trên hoạt động cho trường hợp đó mặc dù.
Chris Up nhẫn

2

Tôi đã thu thập một số giải pháp được đề cập trong các câu trả lời khác và trong các bình luận, sau đó chạy thử nghiệm tốc độ. not set(a).isdisjoint(b)Hóa ra là nhanh nhất, nó cũng không chậm lại nhiều khi kết quả làFalse .

Mỗi trong ba lần chạy kiểm tra một mẫu nhỏ về các cấu hình có thể có ab. Thời gian tính bằng micrô giây.

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

Tôi phải nói rằng tình huống của tôi có thể không phải là điều bạn đang tìm kiếm, nhưng nó có thể cung cấp một sự thay thế cho suy nghĩ của bạn.

Tôi đã thử cả phương thức set () và any () nhưng vẫn gặp vấn đề với tốc độ. Vì vậy, tôi nhớ Raymond Hettinger nói rằng mọi thứ trong python đều là từ điển và sử dụng dict bất cứ khi nào bạn có thể. Vì vậy, đó là những gì tôi đã cố gắng.

Tôi đã sử dụng một defaultdict với int để chỉ ra kết quả âm tính và sử dụng mục trong danh sách đầu tiên làm khóa cho danh sách thứ hai (được chuyển đổi thành defaultdict). Bởi vì bạn đã tra cứu ngay lập tức với dict, bạn biết ngay rằng mục đó có tồn tại trong defaultdict hay không. Tôi biết bạn không phải lúc nào cũng thay đổi cấu trúc dữ liệu cho danh sách thứ hai của mình, nhưng nếu bạn có thể ngay từ đầu, thì nó sẽ nhanh hơn nhiều. Bạn có thể phải chuyển đổi list2 (danh sách lớn hơn) thành defaultdict, trong đó khóa là giá trị tiềm năng bạn muốn kiểm tra từ danh sách nhỏ và giá trị là 1 (nhấn) hoặc 0 (không nhấn, mặc định).

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

Đơn giản.

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

1
Điều này không trả lời câu hỏi. OP muốn biết nếu có bất kỳ giá trị từ danh sách a trong danh sách b.
That1Guy
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.