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]. itertoolsmenawarkan 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:
import itertools
import operator
def most_common(L):
# get an iterable of (item, iterable) pairs
SL = sorted((x, i) for i, x in enumerate(L))
# print 'SL:', SL
groups = itertools.groupby(SL, key=operator.itemgetter(0))
# auxiliary function to get "quality" for an item
def _auxfun(g):
item, iterable = g
count = 0
min_index = len(L)
for _, where in iterable:
count += 1
min_index = min(min_index, where)
# print 'item %r, count %r, minind %r' % (item, count, min_index)
return count, -min_index
# pick the highest-count/earliest item
return max(groups, key=_auxfun)[0]
Ini bisa ditulis lebih ringkas, tentu saja, tapi saya bertujuan untuk kejelasan maksimal. Kedua printpernyataan tersebut dapat dibatalkan komentarnya untuk lebih melihat mesin dalam aksi; misalnya, dengan cetakan yang tidak diomortasikan:
print most_common(['goose', 'duck', 'duck', 'goose'])
memancarkan:
SL: [('duck', 1), ('duck', 2), ('goose', 0), ('goose', 3)]
item 'duck', count 2, minind 1
item 'goose', count 2, minind 0
goose
Seperti yang Anda lihat, SLadalah 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).
groupbydikelompokkan berdasarkan item saja (via operator.itemgetter). Fungsi bantu, disebut sekali per pengelompokan selama maxperhitungan, menerima dan membongkar secara internal grup - tuple dengan dua item di (item, iterable)mana item iterable juga merupakan dua item tupel, (item, original index)[[item SL]].
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 maxoperasi 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 ...:
def most_common(L):
groups = itertools.groupby(sorted(L))
def _auxfun((item, iterable)):
return len(list(iterable)), -L.index(item)
return max(groups, key=_auxfun)[0]
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.indexsetiap 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 :-).
from itertools import groupby as g
def most_common_oneliner(L):
return max(g(sorted(L)), key=lambda(x, v):(len(list(v)),-L.index(x)))[0]