Saya ingin mendapatkan item pertama dari daftar yang cocok dengan suatu syarat. Sangat penting bahwa metode yang dihasilkan tidak memproses seluruh daftar, yang bisa jadi cukup besar. Misalnya, fungsi berikut memadai:
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
Fungsi ini dapat digunakan seperti ini:
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
Namun, saya tidak bisa memikirkan built-in / one-liner yang bagus untuk membiarkan saya melakukan ini. Saya khususnya tidak ingin menyalin fungsi ini jika saya tidak perlu. Apakah ada cara bawaan untuk mendapatkan item pertama yang cocok dengan suatu kondisi?
Jawaban:
Dalam Python 2.6 atau yang lebih baru:
Jika Anda ingin
StopIteration
dinaikkan jika tidak ada elemen yang cocok ditemukan:Jika Anda ingin
default_value
(misalnyaNone
) dikembalikan:Perhatikan bahwa Anda memerlukan sepasang tanda kurung tambahan di sekitar ekspresi generator dalam kasus ini - mereka diperlukan setiap kali ekspresi generator bukan satu-satunya argumen.
Saya melihat sebagian besar jawaban dengan tegas mengabaikan
next
built-in dan jadi saya berasumsi bahwa untuk beberapa alasan misterius mereka 100% fokus pada versi 2.5 dan yang lebih tua - tanpa menyebutkan masalah versi Python (tapi kemudian saya tidak melihat bahwa menyebutkan dalam jawaban yang melakukan menyebutkannext
built-in, yang mengapa saya pikir itu diperlukan untuk memberikan jawaban sendiri - setidaknya "versi yang benar" masalah mendapat catatan cara ini ;-).Dalam 2.5,
.next()
metode iterator segera naikStopIteration
jika iterator segera selesai - yaitu, untuk kasus penggunaan Anda, jika tidak ada item di iterable yang memenuhi syarat. Jika Anda tidak peduli (yaitu, Anda tahu harus ada setidaknya satu item yang memuaskan) maka gunakan saja.next()
(terbaik pada genexp, baris untuknext
built-in di Python 2.6 dan lebih baik).Jika Anda benar- benar peduli, membungkus hal-hal dalam suatu fungsi seperti yang pertama kali Anda tunjukkan dalam Q Anda tampaknya terbaik, dan sementara implementasi fungsi yang Anda usulkan baik-baik saja, Anda bisa menggunakan
itertools
,for...: break
loop, atau genexp, atautry/except StopIteration
sebagai tubuh fungsi sebagai alternatif . , seperti yang disarankan berbagai jawaban. Tidak ada banyak nilai tambah di salah satu alternatif ini jadi saya akan pergi untuk versi sederhana-sederhana yang pertama kali Anda usulkan.sumber
StopIteration
ketika tidak ada elemen ditemukanStopIteration
benar-benar tidak cantik. Lebih baik gunakan metode.Sebagai fungsi yang dapat digunakan kembali, didokumentasikan dan diuji
Versi dengan argumen default
@ zorf menyarankan versi fungsi ini di mana Anda dapat memiliki nilai kembali yang telah ditentukan jika iterable kosong atau tidak memiliki item yang cocok dengan ketentuan:
sumber
StopIteration
adalah pengecualian "dari elemen" kanonik dalam python. Saya tidak melihat masalah dengan itu dilemparkan. Saya mungkin akan menggunakan default "Tidak Ada" yang dapat diteruskan sebagai parameter default ke fungsi.Pengecualian Sialan!
Saya suka jawaban ini . Namun, karena
next()
memunculkanStopIteration
pengecualian ketika tidak ada item, saya akan menggunakan cuplikan berikut untuk menghindari pengecualian:Sebagai contoh,
Akan memunculkan
StopIteration
pengecualian;sumber
Mirip dengan menggunakan
ifilter
, Anda bisa menggunakan ekspresi generator:Dalam kedua kasus, Anda mungkin ingin menangkap
StopIteration
, jika tidak ada elemen yang memenuhi kondisi Anda.Secara teknis, saya kira Anda bisa melakukan sesuatu seperti ini:
Itu akan menghindari membuat
try/except
blok. Tapi itu sepertinya agak kabur dan kasar terhadap sintaksis.sumber
for foo in genex: break
hanya cara melakukanfoo = next(genex)
tanpa membuat tugas jelas dan dengan pengecualian yang akan dinaikkan jika operasi tidak masuk akal terjepit. Mengakhiri dengan kode kegagalan alih-alih menangkap pengecualian biasanya merupakan hal buruk di Python.Cara paling efisien dalam Python 3 adalah salah satu dari yang berikut (menggunakan contoh yang serupa):
Dengan gaya "pemahaman" :
PERINGATAN : Ekspresi bekerja juga dengan Python 2, tetapi dalam contoh ini digunakan
range
yang mengembalikan objek iterable di Python 3 bukannya daftar seperti Python 2 (jika Anda ingin membangun iterable di Python 2 gunakanxrange
saja).Perhatikan bahwa ekspresi menghindari untuk membuat daftar dalam ekspresi pemahaman
next([i for ...])
, yang akan menyebabkan untuk membuat daftar dengan semua elemen sebelum memfilter elemen, dan akan menyebabkan untuk memproses seluruh opsi, alih-alih menghentikan iterasi satu kalii == 1000
.Dengan gaya "fungsional" :
PERINGATAN : Ini tidak bekerja di Python 2, bahkan mengganti
range
denganxrange
karena yangfilter
membuat daftar bukan iterator (tidak efisien), dannext
fungsinya hanya bekerja dengan iterator.Nilai standar
Seperti disebutkan dalam respons lain, Anda harus menambahkan parameter ekstra ke fungsi
next
jika Anda ingin menghindari pengecualian yang muncul ketika kondisi tidak terpenuhi.gaya "fungsional" :
gaya "pemahaman" :
Dengan gaya ini Anda perlu mengelilingi ekspresi pemahaman
()
untuk menghindariSyntaxError: Generator expression must be parenthesized if not sole argument
:sumber
Saya akan menulis ini
sumber
i > 3
harusx > 3
dalam contoh AndaThe
itertools
modul berisi fungsi filter untuk iterator. Elemen pertama dari iterator yang disaring dapat diperoleh dengan memanggilnyanext()
:sumber
i
)filter
dan (i
)map
bisa masuk akal untuk kasus-kasus di mana fungsi yang diterapkan sudah ada, tetapi dalam situasi seperti ini lebih masuk akal hanya dengan menggunakan ekspresi generator.Untuk versi Python yang lebih lama di mana built-in berikutnya tidak ada:
sumber
Dengan menggunakan
satu dapat memeriksa kondisi dari nilai dari item pertama di the_iterable , dan mendapatkan nya indeks tanpa perlu untuk mengevaluasi semua item di the_iterable .
Ekspresi lengkap untuk digunakan adalah
Di sini first_index mengasumsikan nilai dari nilai pertama yang diidentifikasi dalam ekspresi yang dibahas di atas.
sumber
Pertanyaan ini sudah memiliki jawaban yang bagus. Saya hanya menambahkan dua sen karena saya mendarat di sini mencoba mencari solusi untuk masalah saya sendiri, yang sangat mirip dengan OP.
Jika Anda ingin menemukan INDEX dari item pertama yang cocok dengan kriteria menggunakan generator, Anda dapat melakukannya:
sumber
Anda juga bisa menggunakan
argwhere
fungsi ini di Numpy. Sebagai contoh:i) Temukan "l" pertama di "helloworld":
ii) Temukan nomor acak pertama> 0,1
iii) Temukan nomor acak terakhir> 0,1
sumber
Dengan Python 3:
Dengan Python 2.6:
EDIT: Saya pikir itu sudah jelas, tetapi ternyata tidak: alih-alih
None
Anda dapat melewati fungsi (atau alambda
) dengan memeriksa kondisi:sumber
Oneliner:
Jika Anda tidak yakin bahwa elemen apa pun akan valid sesuai dengan kriteria, Anda harus melampirkan ini
try/except
karena[0]
dapat meningkatkanIndexError
.sumber