Bagaimana cara mengurutkan daftar / tupel daftar / tupel berdasarkan elemen pada indeks yang diberikan?

658

Saya memiliki beberapa data baik dalam daftar daftar atau daftar tupel, seperti ini:

data = [[1,2,3], [4,5,6], [7,8,9]]
data = [(1,2,3), (4,5,6), (7,8,9)]

Dan saya ingin mengurutkan berdasarkan elemen ke-2 di subset. Berarti, mengurutkan berdasarkan 2,5,8 dari mana 2berasal (1,2,3), 5berasal dari (4,5,6). Apa cara umum untuk melakukan ini? Haruskah saya menyimpan tupel atau daftar di daftar saya?

Stan
sumber
51
Berkenaan dengan "Haruskah saya menyimpan tupel atau daftar dalam daftar saya?", Aturan praktisnya adalah untuk membuat hal-hal yang abadi sebagai mungkin. Jika Anda tidak perlu memodifikasi sublists di tempat, buatlah tupel.
Matthew Flaschen

Jawaban:

1116
sorted_by_second = sorted(data, key=lambda tup: tup[1])

atau:

data.sort(key=lambda tup: tup[1])  # sorts in place
Stephen
sumber
10
Adakah cara mengurutkannya menjadi lebih kecil?
billwild
63
@ billwild: bantuan (diurutkan). terbalik = Benar.
Stephen
34
@Stephen menggunakan itemgetter lebih cepat dan sederhana: key=itemgetter(1)dan di awal file:from operator import itemgetter
Joschua
3
@Cemre seperti untuk contoh kedua, sortberikut adalah metode Listobjek Python, yang menerima fungsi lambda sebagai keyparameternya. Anda dapat menamainya tup, atau t, atau apa pun yang Anda suka dan itu akan tetap berfungsi. tupdi sini menentukan indeks tupel daftar, sehingga 1berarti penyortiran akan dilakukan oleh nilai kedua tupel dari daftar asli ( 2, 5, 8).
Neurotransmitter
1
Saya agak skeptis terhadap klaim tidak berdasar bahwa "menggunakan itemgetter lebih cepat dan lebih sederhana." Sementara saya secara subyektif menganggap lambdapendekatan intuitif lebih sederhana daripada itemgetterkelas yang itemgetter tidak intuitif , memang tampak lebih cepat . Saya ingin tahu mengapa ini terjadi. Kecurigaan kasar saya adalah bahwa lambdamenimbulkan biaya tersembunyi menangkap semua variabel lokal ke dalam konteks penutupan, sedangkan itemgettercontoh tidak. tl; dr: Selalu gunakan itemgetter, karena kecepatan menang.
Cecil Curry
236
from operator import itemgetter
data.sort(key=itemgetter(1))
manova
sumber
37
Ini harus menjadi jawaban yang diterima. Lihat juga Charlie 's diposting timing , menunjukkan itemgetterkelas untuk menyortir 126% lebih cepat daripada rata-rata setara lambdafungsi.
Cecil Curry
9
Anda juga dapat mengurutkan berdasarkan beberapa indeks secara hierarkis, misalnyadata.sort(key=itemgetter(3,1))
Michael Ohlrogge
57

Saya hanya ingin menambahkan jawaban Stephen jika Anda ingin mengurutkan array dari tinggi ke rendah, cara lain selain dari komentar di atas adalah dengan menambahkan ini ke baris:

reverse = True

dan hasilnya adalah sebagai berikut:

data.sort(key=lambda tup: tup[1], reverse=True)
sifoo
sumber
48

Untuk mengurutkan berdasarkan beberapa kriteria, yaitu misalnya dengan elemen kedua dan ketiga dalam sebuah tuple, mari

data = [(1,2,3),(1,2,1),(1,1,4)]

dan dengan demikian mendefinisikan lambda yang mengembalikan tuple yang menggambarkan prioritas, misalnya

sorted(data, key=lambda tup: (tup[1],tup[2]) )
[(1, 1, 4), (1, 2, 1), (1, 2, 3)]
elm
sumber
28

Jawaban Stephen adalah yang akan saya gunakan. Untuk kelengkapan, inilah pola DSU (menghias-sortir-undecorate) dengan pemahaman daftar:

decorated = [(tup[1], tup) for tup in data]
decorated.sort()
undecorated = [tup for second, tup in decorated]

Atau, lebih tepatnya:

[b for a,b in sorted((tup[1], tup) for tup in data)]

Seperti yang tercantum dalam Python Sorting HowTo , ini sudah tidak perlu sejak Python 2.4, ketika fungsi utama tersedia.

tcarobruce
sumber
2
Jadi jawaban ini berguna untuk Python 2.3-? Apakah ada kegunaan yang valid dalam versi Python lebih saat ini di mana Anda mungkin bisa sedikit menguraikan? Jika tidak, tidak masalah ... baru saja lewat, lihat ini dan paman tua itu harus mengaduk sedikit saja. Ngomong-ngomong, tepuk tangan dan terima kasih atas perjalanan ini kembali ke masa-masa awal Python.
mechanical_meat
19

Untuk mengurutkan daftar tupel (<word>, <count>), untuk countdalam urutan menurun dan worddalam urutan abjad:

data = [
('betty', 1),
('bought', 1),
('a', 1),
('bit', 1),
('of', 1),
('butter', 2),
('but', 1),
('the', 1),
('was', 1),
('bitter', 1)]

Saya menggunakan metode ini:

sorted(data, key=lambda tup:(-tup[1], tup[0]))

dan itu memberi saya hasilnya:

[('butter', 2),
('a', 1),
('betty', 1),
('bit', 1),
('bitter', 1),
('bought', 1),
('but', 1),
('of', 1),
('the', 1),
('was', 1)]
l mingzhi
sumber
1
bagaimana jika tup [1] adalah sebuah string?
eric
12

Tanpa lambda:

def sec_elem(s):
    return s[1]

sorted(data, key=sec_elem)
Mesco
sumber
9

itemgetter()agak lebih cepat daripada lambda tup: tup[1], tetapi peningkatannya relatif sederhana (sekitar 10 hingga 25 persen).

(Sesi IPython)

>>> from operator import itemgetter
>>> from numpy.random import randint
>>> values = randint(0, 9, 30000).reshape((10000,3))
>>> tpls = [tuple(values[i,:]) for i in range(len(values))]

>>> tpls[:5]    # display sample from list
[(1, 0, 0), 
 (8, 5, 5), 
 (5, 4, 0), 
 (5, 7, 7), 
 (4, 2, 1)]

>>> sorted(tpls[:5], key=itemgetter(1))    # example sort
[(1, 0, 0), 
 (4, 2, 1), 
 (5, 4, 0), 
 (8, 5, 5), 
 (5, 7, 7)]

>>> %timeit sorted(tpls, key=itemgetter(1))
100 loops, best of 3: 4.89 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: tup[1])
100 loops, best of 3: 6.39 ms per loop

>>> %timeit sorted(tpls, key=(itemgetter(1,0)))
100 loops, best of 3: 16.1 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: (tup[1], tup[0]))
100 loops, best of 3: 17.1 ms per loop
Walter
sumber
Silakan lihat solusi pengurutan itemgetter untuk berbagai argumen terbalik untuk beberapa kolom di sini, Anda kemudian perlu mengatur pengurutan Anda dalam beberapa langkah berturut-turut: stackoverflow.com/questions/14466068/…
Lorenz
6

@Stephen menjawab langsung ke intinya! Ini adalah contoh untuk visualisasi yang lebih baik,

Berteriaklah untuk penggemar Ready Player One! =)

>>> gunters = [('2044-04-05', 'parzival'), ('2044-04-07', 'aech'), ('2044-04-06', 'art3mis')]
>>> gunters.sort(key=lambda tup: tup[0])
>>> print gunters
[('2044-04-05', 'parzival'), ('2044-04-06', 'art3mis'), ('2044-04-07', 'aech')]

keyadalah fungsi yang akan dipanggil untuk mengubah item koleksi untuk perbandingan .. seperti compareTometode di Jawa.

Parameter yang diteruskan ke kunci harus berupa sesuatu yang dapat dipanggil. Di sini, penggunaan lambdamenciptakan fungsi anonim (yang bisa dipanggil).
Sintaksis lambda adalah kata lambda diikuti oleh nama yang dapat diubah kemudian satu blok kode.

Contoh di bawah ini, kami mengurutkan daftar tuple yang menyimpan info tentang waktu kejadian dan nama aktor tertentu.

Kami menyortir daftar ini berdasarkan waktu kejadian - yang merupakan elemen ke-0 dari sebuah tuple.

Catatan - s.sort([cmp[, key[, reverse]]]) mengurutkan item di tempat

Rishi
sumber
-5

Menyortir tuple cukup sederhana:

tuple(sorted(t))
Jayr
sumber