Atau, secara praktis, bagaimana saya dapat mengurutkan daftar kamus dengan banyak tombol?
Saya punya daftar penis:
b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
{u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
{u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
{u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
{u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
{u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
{u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
{u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
{u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
{u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
{u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
{u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
{u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
{u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
{u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
{u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]
dan saya perlu menggunakan pengurutan multi-kunci yang dibalik oleh Total_Points, lalu tidak dibalik TOT_PTS_Misc
.
Ini dapat dilakukan pada command prompt seperti:
a = sorted(b, key=lambda d: (-d['Total_Points'], d['TOT_PTS_Misc']))
Tetapi saya harus menjalankan ini melalui sebuah fungsi, di mana saya meneruskan daftar dan tombol sortir. Misalnya def multikeysort(dict_list, sortkeys):
,.
Bagaimana garis lambda dapat digunakan yang akan mengurutkan daftar, untuk sejumlah sembarang kunci yang diteruskan ke fungsi multikeysort, dan mempertimbangkan bahwa kunci sortir mungkin memiliki sejumlah kunci dan kunci yang memerlukan pengurutan terbalik akan diidentifikasi dengan '-' sebelumnya?
cmp()
tidak tersedia untuk Python3, jadi saya harus mendefinisikannya sendiri, seperti yang disebutkan di sini: stackoverflow.com/a/22490617/398514cmp
kata kunci, tetapicmp()
fungsinya masih digunakan 4 baris di atas. Saya mencobanya dengan 3.2, 3.3, 3.4 dan 3.5, semuanya gagal pada pemanggilan fungsi, karenacmp()
tidak ditentukan. Poin ketiga di sini ( docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons ) menyebutkan memperlakukancmp()
sebagai hilang.Artikel ini memiliki ikhtisar yang bagus tentang berbagai teknik untuk melakukan ini. Jika persyaratan Anda lebih sederhana daripada "multikey dua arah penuh", lihat. Jelas jawaban yang diterima dan posting blog yang baru saja saya referensikan mempengaruhi satu sama lain dalam beberapa hal, meskipun saya tidak tahu urutan mana.
Jika tautan mati, inilah sinopsis singkat dari contoh yang tidak tercakup di atas:
mylist = sorted(mylist, key=itemgetter('name', 'age')) mylist = sorted(mylist, key=lambda k: (k['name'].lower(), k['age'])) mylist = sorted(mylist, key=lambda k: (k['name'].lower(), -k['age']))
sumber
result = cmp(fn(left), fn(right))
Saya tahu ini adalah pertanyaan yang agak lama, tetapi tidak ada jawaban yang menyebutkan bahwa Python menjamin urutan yang stabil untuk rutinitas penyortirannya seperti
list.sort()
dansorted()
, yang berarti item yang dibandingkan sama mempertahankan urutan aslinya.Artinya padanan
ORDER BY name ASC, age DESC
(menggunakan notasi SQL) untuk daftar kamus dapat dilakukan seperti ini:items.sort(key=operator.itemgetter('age'), reverse=True) items.sort(key=operator.itemgetter('name'))
Perhatikan bagaimana item pertama kali diurutkan berdasarkan atribut "lebih rendah"
age
(menurun), kemudian menurut atribut "major"name
, yang mengarah ke urutan akhir yang benar.Pembalikan / pembalik berfungsi untuk semua jenis yang dapat dipesan, tidak hanya angka yang dapat Anda negasikan dengan meletakkan tanda minus di depan.
Dan karena algoritma Timsort digunakan dalam (setidaknya) CPython, ini sebenarnya lebih cepat dalam praktiknya.
sumber
def sortkeypicker(keynames): negate = set() for i, k in enumerate(keynames): if k[:1] == '-': keynames[i] = k[1:] negate.add(k[1:]) def getit(adict): composite = [adict[k] for k in keynames] for i, (k, v) in enumerate(zip(keynames, composite)): if k in negate: composite[i] = -v return composite return getit a = sorted(b, key=sortkeypicker(['-Total_Points', 'TOT_PTS_Misc']))
sumber
some_string.split(",")
Saya menggunakan yang berikut ini untuk mengurutkan array 2d pada sejumlah kolom
def k(a,b): def _k(item): return (item[a],item[b]) return _k
Ini dapat diperpanjang untuk mengerjakan sejumlah item yang berubah-ubah. Saya cenderung berpikir menemukan pola akses yang lebih baik ke kunci yang dapat diurutkan lebih baik daripada menulis pembanding yang mewah.
>>> data = [[0,1,2,3,4],[0,2,3,4,5],[1,0,2,3,4]] >>> sorted(data, key=k(0,1)) [[0, 1, 2, 3, 4], [0, 2, 3, 4, 5], [1, 0, 2, 3, 4]] >>> sorted(data, key=k(1,0)) [[1, 0, 2, 3, 4], [0, 1, 2, 3, 4], [0, 2, 3, 4, 5]] >>> sorted(a, key=k(2,0)) [[0, 1, 2, 3, 4], [1, 0, 2, 3, 4], [0, 2, 3, 4, 5]]
sumber
Saya memiliki masalah serupa hari ini - saya harus mengurutkan item kamus dengan menurunkan nilai numerik dan dengan nilai string menaik. Untuk mengatasi masalah konflik arah, saya meniadakan nilai integer.
Berikut adalah varian dari solusi saya - yang berlaku untuk OP
sorted(b, key=lambda e: (-e['Total_Points'], e['TOT_PTS_Misc']))
Sangat sederhana - dan bekerja seperti pesona
[{'TOT_PTS_Misc': 'Chappell, Justin', 'Total_Points': 96.0}, {'TOT_PTS_Misc': 'Russo, Brandon', 'Total_Points': 96.0}, {'TOT_PTS_Misc': 'Utley, Alex', 'Total_Points': 96.0}, {'TOT_PTS_Misc': 'Foster, Toney', 'Total_Points': 80.0}, {'TOT_PTS_Misc': 'Lawson, Roman', 'Total_Points': 80.0}, {'TOT_PTS_Misc': 'Lempke, Sam', 'Total_Points': 80.0}, {'TOT_PTS_Misc': 'Gnezda, Alex', 'Total_Points': 78.0}, {'TOT_PTS_Misc': 'Kirks, Damien', 'Total_Points': 78.0}, {'TOT_PTS_Misc': 'Korecz, Mike', 'Total_Points': 78.0}, {'TOT_PTS_Misc': 'Worden, Tom', 'Total_Points': 78.0}, {'TOT_PTS_Misc': 'Burgess, Randy', 'Total_Points': 66.0}, {'TOT_PTS_Misc': 'Harmon, Gary', 'Total_Points': 66.0}, {'TOT_PTS_Misc': 'Smugala, Ryan', 'Total_Points': 66.0}, {'TOT_PTS_Misc': 'Swartz, Brian', 'Total_Points': 66.0}, {'TOT_PTS_Misc': 'Blackwell, Devon', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Blasinsky, Scott', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Bolden, Antonio', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Carter III, Laymon', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Coleman, Johnathan', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Kovach, Alex', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Smith, Ryan', 'Total_Points': 60.0}, {'TOT_PTS_Misc': 'Venditti, Nick', 'Total_Points': 60.0}]
sumber
from operator import itemgetter from functools import partial def _neg_itemgetter(key, d): return -d[key] def key_getter(key_expr): keys = key_expr.split(",") getters = [] for k in keys: k = k.strip() if k.startswith("-"): getters.append(partial(_neg_itemgetter, k[1:])) else: getters.append(itemgetter(k)) def keyfunc(dct): return [kg(dct) for kg in getters] return keyfunc def multikeysort(dict_list, sortkeys): return sorted(dict_list, key = key_getter(sortkeys)
Demonstrasi:
>>> multikeysort([{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 60.0}, {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0}, {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0}], "-Total_Points,TOT_PTS_Misc") [{u'Total_Points': 96.0, u'TOT_PTS_Misc': u'Chappell, Justin'}, {u'Total_Points': 96.0, u'TOT_PTS_Misc': u'Russo, Brandon'}, {u'Total_Points': 60.0, u'TOT_PTS_Misc': u'Utley, Alex'}]
Penguraiannya agak rapuh, tetapi setidaknya memungkinkan jumlah variabel spasi di antara kunci.
sumber
Karena Anda sudah terbiasa dengan lambda, inilah solusi yang tidak terlalu bertele-tele.
>>> def itemgetter(*names): return lambda mapping: tuple(-mapping[name[1:]] if name.startswith('-') else mapping[name] for name in names) >>> itemgetter('a', '-b')({'a': 1, 'b': 2}) (1, -2)
sumber