Jadi saya punya daftar tupel seperti ini:
[(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
Saya ingin daftar ini untuk tupel yang nilai angkanya sama dengan sesuatu.
Jadi jika saya lakukan search(53)
akan mengembalikan nilai indeks2
Adakah cara mudah untuk melakukan ini?
tl; dr
Sebuah generator ekspresi mungkin adalah solusi yang paling performant dan sederhana untuk masalah Anda:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] result = next((i for i, v in enumerate(l) if v[0] == 53), None) # 2
Penjelasan
Ada beberapa jawaban yang memberikan solusi sederhana untuk pertanyaan ini dengan pemahaman daftar. Meskipun jawaban-jawaban ini benar sekali, namun tidak optimal. Bergantung pada kasus penggunaan Anda, mungkin ada manfaat yang signifikan untuk membuat beberapa modifikasi sederhana.
Masalah utama yang saya lihat dengan menggunakan pemahaman daftar untuk kasus penggunaan ini adalah bahwa seluruh daftar akan diproses, meskipun Anda hanya ingin menemukan 1 elemen .
Python menyediakan konstruksi sederhana yang ideal di sini. Ini disebut ekspresi generator . Berikut ini contohnya:
# Our input list, same as before l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] # Call next on our generator expression. next((i for i, v in enumerate(l) if v[0] == 53), None)
Kita dapat mengharapkan metode ini untuk melakukan pada dasarnya sama dengan pemahaman daftar dalam contoh sederhana kita, tetapi bagaimana jika kita bekerja dengan kumpulan data yang lebih besar? Di situlah keuntungan menggunakan metode generator berperan. Daripada membuat daftar baru, kami akan menggunakan daftar Anda yang ada sebagai iterable kami, dan menggunakan
next()
untuk mendapatkan item pertama dari generator kami.Mari kita lihat bagaimana metode ini bekerja secara berbeda pada beberapa kumpulan data yang lebih besar. Ini adalah daftar besar, terbuat dari 10.000.000 + 1 elemen, dengan target kita di awal (terbaik) atau akhir (terburuk). Kami dapat memverifikasi bahwa kedua daftar ini akan bekerja sama menggunakan pemahaman daftar berikut:
Pemahaman daftar
"Kasus terburuk"
worst_case = ([(False, 'F')] * 10000000) + [(True, 'T')] print [i for i, v in enumerate(worst_case) if v[0] is True] # [10000000] # 2 function calls in 3.885 seconds # # Ordered by: standard name # # ncalls tottime percall cumtime percall filename:lineno(function) # 1 3.885 3.885 3.885 3.885 so_lc.py:1(<module>) # 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
"Kasus terbaik"
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000) print [i for i, v in enumerate(best_case) if v[0] is True] # [0] # 2 function calls in 3.864 seconds # # Ordered by: standard name # # ncalls tottime percall cumtime percall filename:lineno(function) # 1 3.864 3.864 3.864 3.864 so_lc.py:1(<module>) # 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Ekspresi generator
Inilah hipotesis saya untuk generator: kita akan melihat bahwa generator akan berkinerja lebih baik secara signifikan dalam kasus terbaik, tetapi serupa dalam kasus terburuk. Peningkatan kinerja ini sebagian besar disebabkan oleh fakta bahwa generator dievaluasi secara malas, yang berarti generator hanya akan menghitung apa yang diperlukan untuk menghasilkan nilai.
Kasus terburuk
# 10000000 # 5 function calls in 1.733 seconds # # Ordered by: standard name # # ncalls tottime percall cumtime percall filename:lineno(function) # 2 1.455 0.727 1.455 0.727 so_lc.py:10(<genexpr>) # 1 0.278 0.278 1.733 1.733 so_lc.py:9(<module>) # 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} # 1 0.000 0.000 1.455 1.455 {next}
Kasus terbaik
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000) print next((i for i, v in enumerate(best_case) if v[0] == True), None) # 0 # 5 function calls in 0.316 seconds # # Ordered by: standard name # # ncalls tottime percall cumtime percall filename:lineno(function) # 1 0.316 0.316 0.316 0.316 so_lc.py:6(<module>) # 2 0.000 0.000 0.000 0.000 so_lc.py:7(<genexpr>) # 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} # 1 0.000 0.000 0.000 0.000 {next}
APA?! Kasus terbaik menghancurkan pemahaman daftar, tetapi saya tidak mengharapkan kasus terburuk kami mengungguli pemahaman daftar sedemikian rupa. Bagaimana itu? Terus terang, saya hanya bisa berspekulasi tanpa penelitian lebih lanjut.
Ambil semua ini dengan sebutir garam, saya belum menjalankan profil yang kuat di sini, hanya beberapa pengujian yang sangat mendasar. Ini seharusnya cukup untuk memahami bahwa ekspresi generator lebih berkinerja untuk jenis pencarian daftar ini.
Perhatikan bahwa ini semua dasar, python built-in. Kami tidak perlu mengimpor apa pun atau menggunakan perpustakaan apa pun.
Saya pertama kali melihat teknik ini untuk mencari di kursus Udacity cs212 dengan Peter Norvig.
sumber
Anda dapat menggunakan pemahaman daftar :
>>> a = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] >>> [x[0] for x in a] [1, 22, 53, 44] >>> [x[0] for x in a].index(53) 2
sumber
Tupel Anda pada dasarnya adalah pasangan nilai kunci - python
dict
- jadi:l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l)[53]
Edit - aha, Anda mengatakan Anda ingin nilai indeks (53, "xuxa"). Jika ini benar - benar yang Anda inginkan, Anda harus mengulang melalui daftar aslinya, atau mungkin membuat kamus yang lebih rumit:
d = dict((n,i) for (i,n) in enumerate(e[0] for e in l)) idx = d[53]
sumber
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l).get(53)
Hmm ... yah, cara sederhana yang terlintas dalam pikiran adalah mengubahnya menjadi dikt
dan akses
d[53]
.EDIT : Ups, salah membaca pertanyaan Anda saat pertama kali. Sepertinya Anda benar-benar ingin mendapatkan indeks tempat menyimpan nomor tertentu. Kalau begitu, coba
dict((t[0], i) for i, t in enumerate(thelist))
alih-alih
dict
pertobatan lama yang biasa . Makad[53]
akan menjadi 2.sumber
Misalkan daftarnya panjang dan angkanya mungkin berulang, pertimbangkan untuk menggunakan tipe SortedList dari modul sortcontainers Python . Jenis SortedList akan secara otomatis mengatur tupel berdasarkan nomor dan memungkinkan pencarian cepat.
Sebagai contoh:
from sortedcontainers import SortedList sl = SortedList([(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]) # Get the index of 53: index = sl.bisect((53,)) # With the index, get the tuple: tup = sl[index]
Ini akan bekerja jauh lebih cepat daripada saran pemahaman daftar dengan melakukan pencarian biner. Saran kamus akan lebih cepat tetapi tidak akan berfungsi jika mungkin ada nomor duplikat dengan string berbeda.
Jika ada nomor duplikat dengan string berbeda maka Anda perlu mengambil satu langkah lagi:
end = sl.bisect((53 + 1,)) results = sl[index:end]
Dengan membagi dua untuk 54, kita akan menemukan indeks akhir untuk potongan kita. Ini akan jauh lebih cepat pada daftar panjang dibandingkan dengan jawaban yang diterima.
sumber
Hanya dengan cara lain.
zip(*a)[0].index(53)
sumber
[k untuk k, v di l jika v == ' delicia ']
di sini l adalah daftar tuple - [(1, "juca"), (22, "james"), (53, "xuxa"), (44, "delicia")]
Dan alih-alih mengubahnya menjadi dict, kami menggunakan pemahaman llist.
*Key* in Key,Value in list, where value = **delicia**
sumber