Bagaimana cara memeriksa apakah salah satu item berikut ada dalam daftar?

220

Saya mencoba menemukan cara singkat untuk melihat apakah ada item berikut dalam daftar, tetapi upaya pertama saya tidak berhasil. Selain menulis fungsi untuk mencapai ini, adalah cara singkat untuk memeriksa apakah salah satu dari beberapa item ada dalam daftar.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True
Deon
sumber
Lucunya, saya memeriksa bagaimana 'dan' berperilaku. 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')is True False False True
Piotr Kamoda

Jawaban:

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

Daftar kosong dan set kosong adalah False, sehingga Anda dapat menggunakan nilai secara langsung sebagai nilai kebenaran.

Joe Koberg
sumber
6
Ide persimpangan memberi saya ide ini. return len (set (a) .ectioners (set (b)))
Deon
13
FWIW - Saya melakukan perbandingan kecepatan, dan solusi pertama yang ditawarkan di sini adalah puasa sejauh ini.
jackiekazil
2
@ user89788 menjawab menggunakan generator jauh lebih cepat lagi, karena anydapat kembali lebih awal segera setelah menemukan Truenilai - itu tidak harus membangun seluruh daftar terlebih dahulu
Anentropic
Solusi set kedua tidak akan berfungsi jika Anda memiliki duplikat dalam daftar (karena set hanya berisi satu dari setiap item). Jika `L1 = [1,1,2,3] 'dan' L2 = [1,2,3] ', semua item akan terlihat berpotongan.
donrondadon
Saya tahu ini hampir 10 tahun, tetapi solusi pertama tampaknya tidak berhasil untuk saya. saya telah mengganti angka dalam L2 untuk string, dan saya mendapatkan kesalahan berikut: TypeError: 'in <string>' memerlukan string sebagai operan kiri, bukan daftar
roastbeeef
227

Ah, Tobias kau mengalahkanku karenanya. Saya sedang memikirkan sedikit variasi pada solusi Anda ini:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True
ojdo
sumber
5
Saya menyadari ini adalah jawaban yang sangat lama, tetapi jika satu daftar sangat panjang dan yang lainnya pendek, apakah ada urutan yang akan menghasilkan kinerja yang lebih cepat? (ie, x in long for x in shortvs x in short for x in long)
Luke Sapan
11
@LukeSapan: Anda benar. Pesanan itu dapat diperoleh melalui "cetak apa saja (x dalam maks (a, b, kunci = len) untuk x dalam min (a, b, kunci = len))". Ini menggunakan x in long untuk x pendeknya.
Nuclearman
2
Ini adalah jawaban terbaik karena menggunakan generator dan akan kembali segera setelah kecocokan ditemukan (seperti yang orang lain katakan, hanya saja tidak pada jawaban ini!).
dotcomly
4
@Nuclearman, hati-hati: Jika dua daftar adan bmemiliki panjang yang sama, max dan min akan kembali meninggalkan sebagian-daftar, yang membuat any()panggilan beroperasi melalui daftar yang sama di kedua sisi. Jika Anda benar-benar membutuhkan memeriksa panjang, membalik urutan daftar dalam panggilan kedua: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart
3
@NoahBogart Anda benar dan solusi itu tampak sebagus apa pun. Saya juga menganggap Anda berarti: any(x in max(a, b, key=len) for x in min(b, a, key=len))(melewatkan min).
Nuclearman
29

Mungkin sedikit lebih malas:

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

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

sumber
1
Ini hampir sama dengan yang saya posting.
Bastien Léonard
5
@ BastienLéonard ... kecuali jauh lebih cepat karena menggunakan generator dan dengan demikian anydapat kembali lebih awal, sedangkan versi Anda harus membangun seluruh daftar dari pemahaman sebelum anydapat menggunakannya. @ jawaban user89788 sedikit lebih baik karena tanda kurung ganda tidak diperlukan
Anentropic
17

Pikirkan tentang apa yang sebenarnya dikatakan kode!

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

Itu mungkin harus menjelaskannya. :) Python rupanya mengimplementasikan "malas atau", yang seharusnya tidak mengejutkan. Melakukannya sesuatu seperti ini:

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

Pada contoh pertama, x == 1dan y == 2. Dalam contoh kedua, itu sebaliknya. Itu sebabnya ia mengembalikan nilai yang berbeda tergantung pada urutannya.

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

Versi kode golf. Pertimbangkan menggunakan set jika masuk akal untuk melakukannya. Saya menemukan ini lebih mudah dibaca daripada pemahaman daftar.

00500005
sumber
12

1 baris tanpa daftar daftar.

>>> 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
Himel Das
sumber
7

Terbaik yang bisa saya kemukakan:

any([True for e in (1, 2) if e in a])
Bastien Léonard
sumber
6

Dalam python 3 kita bisa mulai menggunakan tanda bintang yang belum dibuka. Diberikan dua daftar:

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

Sunting: sertakan saran alkanen

Daniel Braun
sumber
1
@Anthony, ia membuat set yang berisi elemen dalam a, dan set lain yang mengandung elemen dalam b, lalu ia menemukan persimpangan (elemen bersama) antara set dan any () mengembalikan true jika ada elemen seperti itu yang benar. Solusi tidak akan berfungsi jika satu-satunya elemen yang dibagikan adalah falsy (seperti angka 0). Mungkin lebih baik menggunakan len () daripada any ()
alkanen
1
@alkanen Panggilan bagus
Daniel Braun
mengapa tidak menggunakan fungsi set?
Alex78191
5

Ketika Anda berpikir "centang untuk melihat apakah a dalam b", pikirkan hash (dalam hal ini, set). Cara tercepat adalah dengan hash daftar yang ingin Anda periksa, dan kemudian periksa setiap item di sana.

Inilah sebabnya mengapa jawaban Joe Koberg cepat: memeriksa set persimpangan sangat cepat.

Ketika Anda tidak memiliki banyak data, membuat set bisa membuang-buang waktu. Jadi, Anda dapat membuat satu set daftar dan cukup memeriksa setiap item:

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

Ketika jumlah item yang ingin Anda periksa kecil, perbedaannya dapat diabaikan. Tetapi periksa banyak angka terhadap daftar besar ...

tes:

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)

kecepatan:

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

Metode yang secara konsisten cepat adalah membuat satu set (dari daftar), tetapi persimpangan bekerja pada data besar menentukan yang terbaik!

dantiston
sumber
3

Dalam beberapa kasus (misalnya elemen daftar unik), operasi yang ditetapkan dapat digunakan.

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

Atau, menggunakan set.isdisjoint () ,

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

Ini akan melakukannya dalam satu baris.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True
Chris Upchurch
sumber
Saya tidak mendapatkan Benar di sini >>> cetak [2, 3, 4] >>> cetak b [2, 7] >>> mengurangi (lambda x, y: x dalam b, a) Salah
Deon
Ya. Kamu benar. mengurangi () tidak cukup menangani nilai boolean seperti yang saya kira. Versi revisi yang saya tulis di atas berfungsi untuk kasus itu.
Chris Upchurch
2

Saya mengumpulkan beberapa solusi yang disebutkan dalam jawaban lain dan dalam komentar, kemudian menjalankan tes kecepatan. not set(a).isdisjoint(b)ternyata yang tercepat, ternyata juga tidak banyak melambat ketika hasilnya False.

Masing-masing dari tiga tes menjalankan sampel kecil dari kemungkinan konfigurasi adan b. Waktu dalam mikrodetik.

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
mengunyah kaus kaki
sumber
0

Saya harus mengatakan bahwa situasi saya mungkin bukan yang Anda cari, tetapi mungkin memberikan alternatif bagi pemikiran Anda.

Saya telah mencoba metode set () dan any () tetapi masih memiliki masalah dengan kecepatan. Jadi saya ingat Raymond Hettinger mengatakan semuanya dengan python adalah kamus dan gunakan dict kapan pun Anda bisa. Jadi itulah yang saya coba.

Saya menggunakan defaultdict dengan int untuk menunjukkan hasil negatif dan menggunakan item dalam daftar pertama sebagai kunci untuk daftar kedua (dikonversi ke defaultdict). Karena Anda memiliki pencarian instan dengan dict, Anda langsung tahu apakah item itu ada di defaultdict. Saya tahu Anda tidak selalu bisa mengubah struktur data untuk daftar kedua Anda, tetapi jika Anda bisa dari awal, maka itu jauh lebih cepat. Anda mungkin harus mengubah list2 (daftar yang lebih besar) ke defaultdict, di mana kunci adalah nilai potensial yang ingin Anda periksa dari daftar kecil, dan nilainya adalah 1 (klik) atau 0 (tanpa klik, 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
yangliu2
sumber
-4

Sederhana.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass
PyGuy
sumber
1
Ini tidak menjawab pertanyaan. OP ingin tahu apakah ada nilai dari daftar a dalam daftar b.
That1Guy