Ini melakukan apa yang Anda inginkan, dan akan berhasil di hampir semua kasus:
>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True
Ekspresi 'a','b' in ['b', 'a', 'foo', 'bar']
tidak berfungsi seperti yang diharapkan karena Python menafsirkannya sebagai tupel:
>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)
Pilihan lain
Ada cara lain untuk menjalankan pengujian ini, tetapi cara tersebut tidak akan berfungsi untuk berbagai jenis masukan. Seperti yang dikatakan Kabie , Anda dapat menyelesaikan masalah ini menggunakan set ...
>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True
...terkadang:
>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Set hanya dapat dibuat dengan elemen yang dapat dicirikan. Tetapi ekspresi generator all(x in container for x in items)
dapat menangani hampir semua jenis penampung. Satu-satunya persyaratan adalah yang container
dapat diulang (yaitu bukan generator). items
bisa menjadi iterable sama sekali.
>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True
Tes Kecepatan
Dalam banyak kasus, pengujian subset akan lebih cepat daripada all
, tetapi perbedaannya tidak mengejutkan - kecuali jika pertanyaannya tidak relevan karena rangkaian bukanlah pilihan. Mengubah daftar menjadi set hanya untuk tujuan pengujian seperti ini tidak selalu sepadan dengan masalahnya. Dan mengubah generator menjadi set terkadang bisa sangat boros, memperlambat program dengan banyak kali lipat.
Berikut adalah beberapa tolok ukur untuk ilustrasi. Perbedaan terbesar muncul jika keduanya container
dan items
relatif kecil. Dalam hal ini, pendekatan subset adalah tentang urutan besarnya lebih cepat:
>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Ini terlihat seperti perbedaan besar. Tapi selama container
satu set, all
masih bisa digunakan dengan sempurna pada skala yang jauh lebih besar:
>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Menggunakan pengujian subset masih lebih cepat, tetapi hanya sekitar 5x pada skala ini. Peningkatan kecepatan ini disebabkan oleh c
implementasi fast- backed Python set
, tetapi algoritme dasarnya sama dalam kedua kasus.
Jika Anda items
sudah disimpan dalam daftar karena alasan lain, maka Anda harus mengubahnya menjadi satu set sebelum menggunakan pendekatan pengujian subset. Kemudian speedup turun menjadi sekitar 2,5x:
>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Dan jika Anda container
adalah urutan, dan perlu dikonversi terlebih dahulu, maka percepatannya bahkan lebih kecil:
>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Satu-satunya saat kita mendapatkan hasil yang sangat lambat adalah ketika kita pergi container
secara berurutan:
>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Dan tentu saja, kami hanya akan melakukannya jika kami harus. Jika semua item di bigseq
hashable, maka kami akan melakukan ini sebagai gantinya:
>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Itu hanya 1,66x lebih cepat dari alternatif ( set(bigseq) >= set(bigsubseq)
, waktunya di atas pada 4,36).
Jadi pengujian subset umumnya lebih cepat, tetapi tidak dengan margin yang luar biasa. Di sisi lain, mari kita lihat kapan all
lebih cepat. Bagaimana jika items
sepuluh juta nilai panjangnya, dan cenderung memiliki nilai yang tidak ada container
?
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Mengubah generator menjadi satu set ternyata sangat boros dalam hal ini. The set
konstruktor harus mengkonsumsi seluruh pembangkit. Tetapi perilaku hubung singkat all
memastikan bahwa hanya sebagian kecil dari generator yang perlu dikonsumsi, jadi ini lebih cepat daripada pengujian subset dengan empat kali lipat .
Ini adalah contoh ekstrim, harus diakui. Tetapi seperti yang ditunjukkan, Anda tidak dapat berasumsi bahwa satu pendekatan atau yang lain akan lebih cepat dalam semua kasus.
Hasilnya
Sebagian besar waktu, mengonversi container
ke satu set sangat berharga, setidaknya jika semua elemennya dapat di-hash. Itu karena in
untuk himpunan adalah O (1), sedangkan in
untuk sekuens adalah O (n).
Di sisi lain, menggunakan pengujian subset mungkin hanya sesekali bermanfaat. Pasti lakukan jika item pengujian Anda sudah disimpan dalam satu set. Jika tidak, all
hanya sedikit lebih lambat, dan tidak memerlukan penyimpanan tambahan. Ini juga dapat digunakan dengan generator item yang besar, dan terkadang memberikan percepatan besar dalam kasus itu.
set(['a', 'b']) <= set(['b','a','foo','bar'])
adalah cara lain untuk mengeja hal yang sama, dan terlihat "lebih matematis".{'a', 'b'} <= {'b','a','foo','bar'}
Saya cukup yakin
in
memiliki prioritas yang lebih tinggi daripada,
pernyataan Anda diinterpretasikan sebagai'a', ('b' in ['b' ...])
, yang kemudian dievaluasi'a', True
karena'b'
ada dalam array.Lihat jawaban sebelumnya untuk mengetahui cara melakukan apa yang Anda inginkan.
sumber
Jika Anda ingin memeriksa semua kecocokan masukan Anda ,
jika Anda ingin memeriksa setidaknya satu pertandingan ,
sumber
Pengurai Python mengevaluasi pernyataan itu sebagai tupel, di mana nilai pertama adalah
'a'
, dan nilai kedua adalah ekspresi'b' in ['b', 'a', 'foo', 'bar']
(yang mengevaluasi keTrue
).Anda dapat menulis fungsi sederhana melakukan apa yang Anda inginkan, meskipun:
Dan menyebutnya seperti:
sumber
Alasan saya pikir ini lebih baik daripada jawaban yang dipilih adalah karena Anda benar-benar tidak perlu memanggil fungsi 'all ()'. Daftar kosong mengevaluasi ke False dalam pernyataan IF, daftar tidak kosong mengevaluasi ke True.
Contoh:
sumber
Saya akan mengatakan kita bahkan bisa membiarkan tanda kurung siku itu keluar.
sumber
Kedua jawaban yang disajikan di sini tidak akan menangani elemen yang berulang. Misalnya, jika Anda menguji apakah [1,2,2] adalah sublist dari [1,2,3,4], keduanya akan mengembalikan True. Mungkin itu yang ingin Anda lakukan, tetapi saya hanya ingin menjelaskan. Jika Anda ingin mengembalikan false untuk [1,2,2] di [1,2,3,4], Anda perlu mengurutkan kedua daftar dan memeriksa setiap item dengan indeks bergerak pada setiap daftar. Sedikit lebih rumit untuk perulangan.
sumber
bagaimana Anda bisa menjadi pythonic tanpa lambda! .. tidak untuk dianggap serius .. tapi cara ini juga berhasil:
tinggalkan bagian akhir jika Anda ingin menguji apakah ada nilai di dalam array:
sumber
filter
generator. Anda perlu membungkusnyalist
jika Anda ingin benar-benar mendapatkan hasil yang bisa Anda uji dengan==
atau dalam konteks boolean (untuk melihat apakah kosong). Menggunakan pemahaman daftar atau ekspresi generator dalamany
atauall
lebih disukai.Begini cara saya melakukannya:
sumber