Làm cách nào để sắp xếp danh sách / bộ danh sách / bộ dữ liệu theo thành phần tại một chỉ mục nhất định?


657

Tôi có một số dữ liệu trong danh sách danh sách hoặc danh sách các bộ dữ liệu, như thế này:

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

Và tôi muốn sắp xếp theo phần tử thứ 2 trong tập hợp con. Có nghĩa là, sắp xếp theo 2,5,8 từ đâu 2đến (1,2,3), 5là từ (4,5,6). Cách phổ biến để làm điều này là gì? Tôi nên lưu trữ bộ dữ liệu hoặc danh sách trong danh sách của tôi?


51
Liên quan đến "Tôi nên lưu trữ bộ dữ liệu hoặc danh sách trong danh sách của mình?", Một nguyên tắc nhỏ là làm cho mọi thứ trở nên bất biến nhất có thể. Nếu bạn không cần sửa đổi danh sách con tại chỗ, hãy đặt chúng thành bộ dữ liệu.
Matthew Flaschen

Câu trả lời:


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

hoặc là:

data.sort(key=lambda tup: tup[1])  # sorts in place

10
Bất kỳ ý tưởng làm thế nào để sắp xếp nó lớn hơn đến nhỏ hơn?
billwild

63
@billwild: giúp đỡ (sắp xếp). đảo ngược = Đúng.
Stephen

34
@Stephen sử dụng itemgetter nhanh hơn và đơn giản hơn: key=itemgetter(1)và ở phần đầu của tệp:from operator import itemgetter
Joschua

3
@Cemre như ví dụ thứ hai, sortđây là một phương thức của Listđối tượng Python, nhận hàm lambda làm keytham số của nó . Bạn có thể đặt tên nó là tup, hoặc t, hoặc bất cứ điều gì bạn thích và nó vẫn sẽ hoạt động. tupở đây chỉ định chỉ mục của bộ dữ liệu, do đó, 1việc sắp xếp sẽ được thực hiện bởi các giá trị thứ hai của bộ dữ liệu từ danh sách gốc ( 2, 5, 8).
Chất dẫn truyền thần kinh

1
Tôi đã hơi hoài nghi về tuyên bố không có căn cứ rằng "sử dụng itemgetter nhanh hơn và đơn giản hơn". Trong khi tôi chủ quan coi lambdacách tiếp cận trực quan đơn giản hơn itemgetterlớp không trực quan ,itemgetter không nhưng thực sự có vẻ nhanh hơn . Tôi tò mò về lý do tại sao điều này là. Sự nghi ngờ thô thiển của tôi là một lambdachi phí phát sinh khi nắm bắt tất cả các biến cục bộ vào bối cảnh đóng cửa, trong khi một itemgettertrường hợp thì không. tl; dr: Luôn luôn sử dụng itemgetter, vì tốc độ chiến thắng.
Cecil Curry

235
from operator import itemgetter
data.sort(key=itemgetter(1))

37
Đây phải là câu trả lời được chấp nhận. Xem thêm thời gian đăng của Charlie , chứng minh lớp sắp xếp trung bình nhanh hơn 126% so với chức năng tương đương . itemgetterlambda
Cà ri

9
Bạn cũng có thể sắp xếp theo nhiều chỉ số phân cấp, ví dụ nhưdata.sort(key=itemgetter(3,1))
Michael Ohlrogge

57

Tôi chỉ muốn thêm vào câu trả lời của Stephen nếu bạn muốn sắp xếp mảng từ cao xuống thấp, một cách khác ngoài các ý kiến ​​trên chỉ là thêm điều này vào dòng:

reverse = True

và kết quả sẽ như sau:

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

48

Để sắp xếp theo nhiều tiêu chí, cụ thể là các phần tử thứ hai và thứ ba trong một tuple, hãy để

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

và vì vậy, xác định một lambda trả về một tuple mô tả mức độ ưu tiên, ví dụ

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

28

Câu trả lời của Stephen là câu tôi muốn sử dụng. Để hoàn thiện, đây là mẫu DSU (trang trí sắp xếp-không trang trí) với danh sách hiểu:

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

Hoặc, chặt chẽ hơn:

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

Như đã lưu ý trong Hướng dẫn sắp xếp Python , điều này không cần thiết kể từ Python 2.4, khi các chức năng chính trở nên khả dụng.


2
Vì vậy, câu trả lời này hữu ích cho Python 2.3-? Có bất kỳ sử dụng hợp lệ trong các phiên bản Python hiện tại xung quanh mà bạn có thể xây dựng một chút không? Nếu không, không bận tâm ... chỉ là đi ngang qua, đã thấy điều này và noggin cũ phải khuấy động chỉ một chút. Dù sao, chúc mừng và cảm ơn vì đã quay trở lại những ngày đầu của Python.
Mechanical_meat

19

Để sắp xếp danh sách các bộ dữ liệu (<word>, <count>), counttheo thứ tự giảm dần và wordtheo thứ tự bảng chữ cái:

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

Tôi sử dụng phương pháp này:

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

và nó cho tôi kết quả:

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

1
Nếu tup [1] là một chuỗi thì sao?
eric

12

Không có lambda:

def sec_elem(s):
    return s[1]

sorted(data, key=sec_elem)

9

itemgetter() có phần nhanh hơn lambda tup: tup[1] , nhưng mức tăng tương đối khiêm tốn (khoảng 10 đến 25 phần trăm).

(Phiên 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

Vui lòng xem giải pháp sắp xếp itemgetter để thay đổi các đối số ngược cho nhiều cột ở đây, sau đó bạn cần sắp xếp sắp xếp theo nhiều bước liên tiếp: stackoverflow.com/questions/14466068/iêu
Lorenz

6

Câu trả lời của @Stephen là đến điểm! Dưới đây là một ví dụ để hình dung tốt hơn,

Hét lên cho người hâm mộ 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')]

key là một chức năng sẽ được gọi để chuyển đổi các mục của bộ sưu tập để so sánh .. như compareTo phương thức trong Java.

Tham số được truyền cho khóa phải là một cái gì đó có thể gọi được. Ở đây, việc sử dụnglambda tạo một hàm ẩn danh (có thể gọi được).
Cú pháp của lambda là từ lambda theo sau là một tên lặp sau đó là một khối mã duy nhất.

Dưới đây ví dụ, chúng tôi đang sắp xếp một danh sách các tuple chứa thời gian abt thông tin của một số sự kiện và tên diễn viên nhất định.

Chúng tôi đang sắp xếp danh sách này theo thời gian xảy ra sự kiện - đó là yếu tố thứ 0 của một bộ dữ liệu.

Lưu ý - s.sort([cmp[, key[, reverse]]]) sắp xếp các mục của s tại chỗ


-5

Sắp xếp một tuple khá đơn giản:

tuple(sorted(t))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.