Sắp xếp danh sách Python theo hai trường


172

Tôi có danh sách sau đây được tạo từ một csv được sắp xếp

list1 = sorted(csv1, key=operator.itemgetter(1))

Tôi thực sự muốn sắp xếp danh sách theo hai tiêu chí: đầu tiên theo giá trị trong trường 1 và sau đó theo giá trị trong trường 2. Làm thế nào để tôi làm điều này?



Chúng ta có để câu hỏi này đứng và chỉ giới hạn phạm vi của nó thành "list-of-list-of-length-hai-buildin-type (ví dụ: chuỗi / int / float)" . Hoặc chúng ta cũng cho phép "danh sách đối tượng xác định người dùng" , như tiêu đề gợi ý cũng được cho phép, trong trường hợp đó câu trả lời là "Xác định __lt__()phương thức trên lớp của bạn hoặc kế thừa từ một lớp nào đó" ? Điều đó sẽ làm cho nó một kinh điển tốt hơn nhiều.
smci

Câu trả lời:


157

như thế này:

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))

1
+1: Thanh lịch hơn của tôi. Tôi quên rằng itemgetter có thể mất nhiều chỉ số.
dappawit

7
operatorlà một mô-đun cần phải được nhập khẩu.
bẫy bẫy

3
Tôi sẽ tiến hành như thế nào nếu tôi muốn sắp xếp tăng dần trên một yếu tố và giảm dần trên yếu tố khác, sử dụng itemgetter ??.
tro bụi

3
@ashish, hãy xem câu trả lời của tôi dưới đây với các hàm lambda, điều này rõ ràng, sắp xếp theo "-x [1]" hoặc thậm chí "x [0] + x [1]" nếu bạn muốn
jaap

Nếu một tiêu chí trong chế độ đảo ngược thì sao?
YaserKH

328

Không cần nhập bất cứ thứ gì khi sử dụng chức năng lambda.
Các loại sau sắp xếp listtheo phần tử thứ nhất, sau đó theo phần tử thứ hai.

sorted(list, key=lambda x: (x[0], -x[1]))

12
Đẹp. Như bạn đã lưu ý trong nhận xét cho câu trả lời chính ở trên, đây là cách tốt nhất (duy nhất?) Để thực hiện nhiều loại với các thứ tự sắp xếp khác nhau. Có lẽ làm nổi bật điều đó. Ngoài ra, văn bản của bạn không chỉ ra rằng bạn đã sắp xếp giảm dần trên phần tử thứ hai.
PeterVermont

2
@ user1700890 Tôi đã giả sử trường đã là chuỗi. Nó nên sắp xếp các chuỗi theo thứ tự chữ cái theo mặc định. Bạn nên đăng riêng câu hỏi của mình lên SO nếu nó không liên quan cụ thể đến câu trả lời ở đây hoặc câu hỏi ban đầu của OP.
pbible

5
những gì hiện các -trong -x[1]đứng cho?
Tháng Một

7
@jan sắp xếp ngược lại
jaap

3
Sẽ không làm việc trong một trường hợp cụ thể. Các giải pháp được chấp nhận cũng sẽ không hoạt động. Ví dụ: các cột được sử dụng làm khóa là tất cả các chuỗi không thể chuyển đổi thành số. Thứ hai, người ta muốn sắp xếp theo thứ tự tăng dần theo một cột và thứ tự giảm dần theo cột khác.
coder.in.me

20

Python có một loại sắp xếp ổn định, do đó với điều kiện hiệu năng không phải là vấn đề, cách đơn giản nhất là sắp xếp nó theo trường 2 và sau đó sắp xếp lại theo trường 1.

Điều đó sẽ mang lại cho bạn kết quả mà bạn muốn, điều hấp dẫn duy nhất là nếu đó là một danh sách lớn (hoặc bạn muốn sắp xếp nó thường xuyên) thì việc gọi sắp xếp hai lần có thể là một chi phí không thể chấp nhận được.

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))

Làm theo cách này cũng giúp bạn dễ dàng xử lý tình huống mà bạn muốn một số cột được sắp xếp ngược lại, chỉ cần bao gồm tham số 'Reverse = True' khi cần thiết.

Nếu không, bạn có thể truyền nhiều tham số cho itemgetter hoặc tự tạo một tuple. Điều đó có thể sẽ nhanh hơn, nhưng có một vấn đề là nó không khái quát tốt nếu một số cột muốn được sắp xếp ngược lại (các cột số vẫn có thể được đảo ngược bằng cách phủ định chúng nhưng điều đó ngăn việc sắp xếp ổn định).

Vì vậy, nếu bạn không cần bất kỳ cột nào được sắp xếp ngược lại, hãy chuyển nhiều đối số sang itemgetter, nếu bạn có thể và các cột không phải là số hoặc bạn muốn giữ ổn định sắp xếp cho nhiều loại liên tiếp.

Chỉnh sửa: Đối với những người bình luận có vấn đề hiểu cách trả lời câu hỏi ban đầu, đây là một ví dụ cho thấy chính xác tính chất ổn định của việc sắp xếp đảm bảo chúng ta có thể phân loại riêng biệt trên mỗi khóa và kết thúc với dữ liệu được sắp xếp theo nhiều tiêu chí:

DATA = [
    ('Jones', 'Jane', 58),
    ('Smith', 'Anne', 30),
    ('Jones', 'Fred', 30),
    ('Smith', 'John', 60),
    ('Smith', 'Fred', 30),
    ('Jones', 'Anne', 30),
    ('Smith', 'Jane', 58),
    ('Smith', 'Twin2', 3),
    ('Jones', 'John', 60),
    ('Smith', 'Twin1', 3),
    ('Jones', 'Twin1', 3),
    ('Jones', 'Twin2', 3)
]

# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])

for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

Đây là một ví dụ có thể chạy được, nhưng để cứu người đang chạy nó, đầu ra là:

Initial data in random order
Jones      Jane       58
Smith      Anne       30
Jones      Fred       30
Smith      John       60
Smith      Fred       30
Jones      Anne       30
Smith      Jane       58
Smith      Twin2      3
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Jones      Twin2      3

First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Jones      Jane       58
Smith      Jane       58
Smith      John       60
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith      John       60
Jones      John       60
Jones      Jane       58
Smith      Jane       58
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.

Jones      John       60
Jones      Jane       58
Jones      Anne       30
Jones      Fred       30
Jones      Twin1      3
Jones      Twin2      3
Smith      John       60
Smith      Jane       58
Smith      Anne       30
Smith      Fred       30
Smith      Twin1      3
Smith      Twin2      3

Đặc biệt lưu ý cách thức trong bước thứ hai, reverse=Truetham số giữ các tên đầu tiên theo thứ tự trong khi chỉ cần sắp xếp sau đó đảo ngược danh sách sẽ mất thứ tự mong muốn cho khóa sắp xếp thứ ba.


1
Sắp xếp ổn định không có nghĩa là nó sẽ không quên cách sắp xếp trước đó của bạn. Câu trả lời này là sai.
Mike Axiak

7
Sắp xếp ổn định có nghĩa là bạn có thể sắp xếp theo cột a, b, c đơn giản bằng cách sắp xếp theo cột c rồi b rồi a. Trừ khi bạn quan tâm để mở rộng bình luận của bạn, tôi nghĩ rằng đó là bạn bị nhầm lẫn.
Duncan

7
Câu trả lời này hoàn toàn chính xác, mặc dù đối với các danh sách lớn hơn thì không rõ ràng: nếu danh sách đã được sắp xếp một phần, thì bạn sẽ mất phần lớn việc tối ưu hóa sắp xếp của Python bằng cách xáo trộn danh sách xung quanh nhiều hơn nữa. @Mike, bạn không chính xác; Tôi đề nghị thực sự kiểm tra câu trả lời trước khi tuyên bố chúng sai.
Glenn Maynard

6
@MikeAxiak: docs.python.org/2/library/stdtypes.html#index-29 bang trong bình luận 9: Bắt đầu với Python 2.3, phương pháp sắp xếp () là đảm bảo được ổn định. Một loại là ổn định nếu nó đảm bảo không thay đổi thứ tự tương đối của các yếu tố so sánh bằng nhau - điều này hữu ích cho việc sắp xếp theo nhiều lượt (ví dụ: sắp xếp theo bộ phận, sau đó theo mức lương).
bẫy

Điều này không đúng vì điều này không trả lời câu hỏi mà anh ta hỏi. anh ta muốn một danh sách được sắp xếp theo chỉ mục đầu tiên và trong trường hợp có mối quan hệ trong chỉ mục đầu tiên, anh ta muốn sử dụng chỉ mục thứ hai làm tiêu chí sắp xếp. Một loại ổn định chỉ đảm bảo rằng tất cả mọi thứ đều bằng nhau, thứ tự ban đầu được thông qua sẽ là thứ tự các mục xuất hiện.
Jon

14
list1 = sorted(csv1, key=lambda x: (x[1], x[2]) )

4
Tôi không nghĩ tuple()có thể nhận được hai đối số (hay đúng hơn là ba, nếu bạn tính đến self)
Filipe Correia

3
tuple chỉ mất có thể mất một đối số
therealprashant

1
returntuyên bố nên return tuple((x[1], x[2]))hoặc đơn giản return x[1], x[2]. Tham khảo câu trả lời @jaap bên dưới nếu bạn đang tìm cách sắp xếp theo các hướng khác nhau
Jo Kachikaran

Vì vậy tuple(x[1:3]), nếu bạn muốn sử dụng hàm tạo tuple vì một số lý do thay vì chỉ một danh sách hiển thị tuple x[1], x[2]. Hoặc keyfunc = operator.itemgetter(1, 2)thậm chí không tự viết một chức năng.
abarnert

3
employees.sort(key = lambda x:x[1])
employees.sort(key = lambda x:x[0])

Chúng tôi cũng có thể sử dụng .sort với lambda 2 lần vì sắp xếp python và ổn định. Điều này trước tiên sẽ sắp xếp danh sách theo yếu tố thứ hai, x [1]. Sau đó, nó sẽ sắp xếp phần tử đầu tiên, x [0] (mức ưu tiên cao nhất).

employees[0] = Employee's Name
employees[1] = Employee's Salary

Điều này tương đương với việc thực hiện như sau: staff.sort (key = lambda x: (x [0], x [1]))


1
không, quy tắc sắp xếp này cần được ưu tiên sau đó thứ hai.
CodeFarmer

1

Theo thứ tự tăng dần, bạn có thể sử dụng:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]))

hoặc theo thứ tự giảm dần bạn có thể sử dụng:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]),reverse=True)

0

Sắp xếp danh sách các dicts sử dụng dưới đây sẽ sắp xếp danh sách theo thứ tự giảm dần trên cột đầu tiên là lương và cột thứ hai theo tuổi

d=[{'salary':123,'age':23},{'salary':123,'age':25}]
d=sorted(d, key=lambda i: (i['salary'], i['age']),reverse=True)

Đầu ra: [{'mức lương': 123, 'tuổi': 25}, {'mức lương': 123, 'tuổi': 23}]

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.