Apa cara yang efisien untuk menemukan elemen paling umum dalam daftar Python?
Item daftar saya mungkin tidak dapat hash jadi tidak bisa menggunakan kamus. Juga jika menarik item dengan indeks terendah harus dikembalikan. Contoh:
>>> most_common(['duck', 'duck', 'goose'])
'duck'
>>> most_common(['goose', 'duck', 'duck', 'goose'])
'goose'
Jawaban:
Dengan begitu banyak solusi yang diajukan, saya kagum tidak ada yang mengusulkan apa yang saya anggap sebagai solusi yang jelas (untuk elemen-elemen yang tidak dapat hash tetapi sebanding) - [
itertools.groupby
] [1].itertools
menawarkan fungsionalitas yang cepat dan dapat digunakan kembali, dan memungkinkan Anda mendelegasikan beberapa logika rumit ke komponen perpustakaan standar yang telah teruji dengan baik. Pertimbangkan misalnya:Ini bisa ditulis lebih ringkas, tentu saja, tapi saya bertujuan untuk kejelasan maksimal. Kedua
print
pernyataan tersebut dapat dibatalkan komentarnya untuk lebih melihat mesin dalam aksi; misalnya, dengan cetakan yang tidak diomortasikan:memancarkan:
Seperti yang Anda lihat,
SL
adalah daftar pasangan, setiap pasangan item diikuti oleh indeks item dalam daftar asli (untuk menerapkan kondisi kunci itu, jika item "paling umum" dengan jumlah tertinggi yang sama adalah> 1, hasilnya harus menjadi yang paling awal terjadi).groupby
dikelompokkan berdasarkan item saja (viaoperator.itemgetter
). Fungsi bantu, disebut sekali per pengelompokan selamamax
perhitungan, menerima dan membongkar secara internal grup - tuple dengan dua item di(item, iterable)
mana item iterable juga merupakan dua item tupel,(item, original index)
[[itemSL
]].Kemudian fungsi bantu menggunakan loop untuk menentukan jumlah entri dalam iterable grup, dan indeks asli minimum; itu mengembalikan mereka sebagai "kunci kualitas" gabungan, dengan tanda indeks min-diubah sehingga
max
operasi akan mempertimbangkan "lebih baik" item-item yang terjadi sebelumnya dalam daftar asli.Kode ini bisa jauh lebih sederhana jika khawatir sedikit tentang masalah besar-O dalam ruang dan waktu, misalnya ...:
ide dasar yang sama, hanya diekspresikan lebih sederhana dan padat ... tetapi, sayangnya, ruang tambahan O (N) tambahan (untuk mewujudkan iterables grup untuk daftar) dan O (N kuadrat) waktu (untuk mendapatkan
L.index
setiap item) . Sementara optimasi prematur adalah akar dari semua kejahatan dalam pemrograman, sengaja memilih pendekatan O (N kuadrat) ketika O (N log N) satu tersedia hanya berjalan terlalu banyak melawan butir skalabilitas! -)Akhirnya, bagi mereka yang lebih suka "oneliners" untuk kejelasan dan kinerja, bonus versi 1-liner dengan nama-nama yang dicoret :-).
sumber
groupby
membutuhkan pengurutan terlebih dahulu (O (NlogN)); menggunakanCounter()
denganmost_common()
dapat mengalahkan itu karena menggunakan heapq untuk menemukan item frekuensi tertinggi (hanya 1 item, itu waktu O (N)). SepertiCounter()
sekarang sangat dioptimalkan (penghitungan terjadi dalam loop C), itu dapat dengan mudah mengalahkan solusi ini bahkan untuk daftar kecil. Itu mengeluarkannya dari air untuk daftar besar.Satu kalimat sederhana:
sumber
set(lst)
, seluruh daftar harus diperiksa lagi) ... Mungkin cukup cepat untuk sebagian besar menggunakan, meskipun ...set(lst)
denganlst
dan itu akan bekerja dengan elemen yang tidak dapat di-hash juga; meskipun lebih lambat.list.count()
harus melintasi daftar secara penuh , dan Anda melakukannya untuk setiap item unik dalam daftar. Ini menjadikan ini solusi O (NK) (O (N ^ 2) dalam kasus terburuk). MenggunakanCounter()
hanya membutuhkan O (N) waktu!Meminjam dari sini , ini dapat digunakan dengan Python 2.7:
Bekerja sekitar 4-6 kali lebih cepat daripada solusi Alex, dan 50 kali lebih cepat daripada one-liner yang diusulkan oleh newacct.
Untuk mengambil elemen yang muncul pertama dalam daftar jika terjadi ikatan:
sumber
most_common
disortir berdasarkan jumlah, bukan unordered. Yang mengatakan, itu tidak akan memilih elemen pertama dalam hal ikatan; Saya telah menambahkan cara lain untuk menggunakan penghitung yang memilih elemen pertama.Apa yang Anda inginkan dikenal dalam statistik sebagai mode, dan Python tentu saja memiliki fungsi bawaan untuk melakukan hal itu untuk Anda:
Perhatikan bahwa jika tidak ada "elemen paling umum" seperti kasus di mana dua teratas terikat , ini akan meningkat
StatisticsError
, karena secara statistik, tidak ada mode dalam kasus ini.sumber
set
, dan masuk akalO(n^3)
.Jika tidak hashable, Anda dapat mengurutkannya dan melakukan satu putaran atas hasil penghitungan item (item yang identik akan bersebelahan). Tetapi mungkin lebih cepat untuk membuatnya hashable dan menggunakan dict.
sumber
Counter()
solusi AlexIni adalah solusi O (n).
(terbalik digunakan untuk memastikan bahwa ia mengembalikan item indeks terendah)
sumber
Tanpa persyaratan tentang indeks terendah, Anda dapat menggunakan
collections.Counter
ini:sumber
Urutkan salinan daftar dan temukan jangka waktu terpanjang. Anda dapat menghiasi daftar sebelum mengurutkannya dengan indeks setiap elemen, dan kemudian memilih menjalankan yang dimulai dengan indeks terendah dalam kasus dasi.
sumber
Satu kalimat:
sumber
sumber
Solusi satu garis sederhana
Ini akan mengembalikan elemen yang paling sering dengan frekuensinya.
sumber
Anda mungkin tidak membutuhkan ini lagi, tetapi ini adalah apa yang saya lakukan untuk masalah yang sama. (Terlihat lebih panjang daripada karena komentar.)
sumber
Membangun jawaban Luiz , tetapi memuaskan kondisi " jika menarik item dengan indeks terendah harus dikembalikan " kondisi:
Contoh:
sumber
Sini:
Saya merasa tidak jelas ada metode di suatu tempat di perpustakaan standar yang akan memberi Anda hitungan setiap elemen, tetapi saya tidak dapat menemukannya.
sumber
Ini adalah solusi lambat yang jelas (O (n ^ 2)) jika penyortiran atau hashing tidak layak, tetapi perbandingan kesetaraan (
==
) tersedia:Tetapi membuat barang-barang Anda mudah dipilah atau disortir (seperti yang direkomendasikan oleh jawaban lain) akan hampir selalu membuat menemukan elemen yang paling umum lebih cepat jika panjang daftar Anda (n) besar. O (n) rata-rata dengan hashing, dan O (n * log (n)) paling buruk untuk penyortiran.
sumber
sumber
Saya perlu melakukan ini dalam program terbaru. Saya akui, saya tidak bisa mengerti jawaban Alex, jadi inilah yang akhirnya saya dapatkan.
Saya menghitung waktu untuk solusi Alex dan sekitar 10-15% lebih cepat untuk daftar pendek, tetapi begitu Anda menggunakan lebih dari 100 elemen atau lebih (diuji hingga 200000) sekitar 20% lebih lambat.
sumber
Hai ini adalah solusi yang sangat sederhana dengan O besar (n)
Di mana nomor elemen dalam daftar yang mengulang sebagian besar waktu
sumber
sumber
sumber
sumber