Saya ingin cara idiomatis untuk menemukan elemen pertama dalam daftar yang cocok dengan predikat.
Kode saat ini sangat jelek:
[x for x in seq if predicate(x)][0]
Saya sudah berpikir untuk mengubahnya menjadi:
from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()
Tapi pasti ada sesuatu yang lebih elegan ... Dan alangkah baiknya jika mengembalikan None
nilai daripada menaikkan pengecualian jika tidak ada kecocokan yang ditemukan.
Saya tahu saya bisa mendefinisikan fungsi seperti:
def get_first(predicate, seq):
for i in seq:
if predicate(i): return i
return None
Tetapi cukup hambar untuk mulai mengisi kode dengan fungsi-fungsi utilitas seperti ini (dan orang-orang mungkin tidak akan menyadari bahwa mereka sudah ada di sana, sehingga mereka cenderung untuk diulangi dari waktu ke waktu) jika ada seluk-beluk internal yang sudah menyediakan hal yang sama.
Jawaban:
Untuk menemukan elemen pertama dalam urutan
seq
yang cocok denganpredicate
:Atau (
itertools.ifilter
di Python 2) :Itu memunculkan
StopIteration
jika tidak ada.Untuk kembali
None
jika tidak ada elemen seperti itu:Atau:
sumber
next
yang digunakan alih-alih menaikkan pengecualian.next()
tersedia sejak Python 2.6 Anda bisa membaca halaman What's New untuk membiasakan diri dengan fitur baru dengan cepat.seq.find(&method(:predicate))
atau bahkan lebih ringkas untuk metode contoh misalnya:[1,1,4].find(&:even?)
ifilter
diganti namanya menjadifilter
dalam Python 3.Anda bisa menggunakan ekspresi generator dengan nilai default dan kemudian
next
:Meskipun untuk one-liner ini Anda harus menggunakan Python> = 2.6.
Artikel yang agak populer ini lebih lanjut membahas masalah ini: Fungsi find-in-list Python terbersih? .
sumber
Saya tidak berpikir ada yang salah dengan solusi yang Anda ajukan dalam pertanyaan Anda.
Dalam kode saya sendiri, saya akan mengimplementasikannya seperti ini:
Sintaks dengan
()
menciptakan generator, yang lebih efisien daripada menghasilkan semua daftar sekaligus[]
.sumber
[]
Anda mungkin mengalami masalah jika iterator tidak pernah berakhir atau elemen-elemennya sulit dibuat, semakin lambat ...'generator' object has no attribute 'next'
pada Python 3.Jawaban JF Sebastian paling elegan tetapi membutuhkan python 2.6 seperti yang ditunjukkan fortran.
Untuk versi Python <2.6, ini yang terbaik yang bisa saya lakukan:
Atau jika Anda membutuhkan daftar nanti (daftar menangani StopIteration), atau Anda membutuhkan lebih dari sekadar yang pertama tetapi masih belum semuanya, Anda dapat melakukannya dengan islice:
UPDATE: Meskipun saya secara pribadi menggunakan fungsi yang telah ditentukan yang disebut first () yang menangkap StopIteration dan mengembalikan None, Berikut adalah kemungkinan peningkatan atas contoh di atas: hindari menggunakan filter / ifilter:
sumber