2016-01-14 19 views
9

Tôi cố gắng để sắp xếp một danh sách các hàng như thế này:Sắp xếp các cấp trong Python

[('Pineapple', 1), ('Orange', 3), ('Banana', 1), ('Apple', 1), ('Cherry', 2)] 

Danh sách được sắp xếp nên là:

[('Orange', 3), ('Cherry', 2), ('Apple', 1), ('Banana', 1), ('Pineapple', 1)] 

Vì vậy, ở đây 1 danh sách sẽ được sắp xếp dựa trên tuple[1] theo thứ tự giảm dần, sau đó nếu giá trị tuple (tuple[1]) khớp với Apple, Banana & Pineapple - danh sách phải được sắp xếp thêm dựa trên tuple[0] trong ascendi ng trật tự.

Tôi đã thử các thể ways-

top_n.sort(key = operator.itemgetter(1, 0), reverse = True) 
# Output: [(Orange, 3), (Cherry, 2), (Pineapple, 1), (Banana, 1), (Apple, 1)] 

như "reverse = True", dứa, sau đó Banana, ...

Cuối cùng tôi đã phải đưa ra một giải pháp:

top_n.sort(key = operator.itemgetter(0), reverse = False) 
top_n.sort(key = operator.itemgetter(1), reverse = True) 

Có cách nào tốt hơn để có được giải pháp như cách tiếp cận thứ nhất của tôi không. Tôi đang cố gắng khám phá thêm về Python, do đó tìm kiếm loại giải pháp như vậy.

+0

Thực tế bạn có thể chỉ cần làm: 'top_n.sort(); top_n.sort (key = itemgetter (1), reverse = True) '. Bởi vì 'reverse = False' là mặc định. Cũng sử dụng 'itemgetter (0)' không thực sự có ý nghĩa quá nhiều vì các chuỗi đã được sắp xếp bởi phần tử đầu tiên trước tiên, do đó bạn có thể đơn giản tránh sử dụng 'khóa'. – Bakuriu

+0

@Bakuriu: Yeah! Thật. Cám ơn vì sự gợi ý. –

Trả lời

2

Trong trường hợp của bạn, Martijn Pieters giải pháp có lẽ là tốt nhất, nhưng tôi đã xem xét những gì bạn sẽ làm gì nếu bạn cần phải làm điều này cho bất kỳ số lượng các thông số, và cần phải làm một số tăng dần và một số giảm dần.

Cách tiếp cận này tạo ra một hàm để tạo chỉ mục sắp xếp khi đang di chuyển. Gọi hàm getortfunction với danh sách các bộ để sắp xếp và danh sách chứa các chỉ mục và nếu chúng theo thứ tự ngược lại (ví dụ (2,True) có nghĩa là chỉ số thứ hai theo thứ tự ngược lại), trả về một hàm tạo chỉ mục sắp xếp cho một đối tượng. Đó là khá xấu xí, nhưng linh hoạt.

def getsortfunction(values,indices): 
    sorts = [sorted(list(set(x[indices[i][0]] for x in values)),reverse=indices[i][1]) for i in range(len(indices))] 
    def sortfunction(y): 
     return tuple(sorts[i].index(y[indices[i][0]]) for i in range(len(indices))) 
    return sortfunction 

Ví dụ

a = [('Pineapple',1),('Orange',3),('Banana',1),('Apple',1),('Cherry',2)] 
# sort a by index 1 first (in reverse order) and then by index 0 in non-reverse order 
b = sorted(a,key=getsortfunction(a,[(1,True),(0,False)])) # gives desired list 

Với thêm một tiêu chí

c = [('Pineapple',1,'Hawaii'),('Orange',3,'Florida'),('Banana',1,'Hawaii'),('Apple',1,'Washington'),('Cherry',2,'Washington')] 
# sort first by number (in reverse order) then by state, and finally by fruit 
d = sorted(c,key=getsortfunction(c,[(1,True),(2,False),(0,False)])) 

# sort c first by number (in reverse order), then by fruit, ignoring state 
e = sorted(c,key=getsortfunction(c,[(1,True),(0,False)])) 

Các getsortfunction đầu tiên xây dựng một danh sách lồng nhau của các giá trị duy nhất theo thứ tự và trả về một chức năng mà bản đồ mỗi giá trị được sắp xếp để một bộ dữ liệu số cho các chỉ mục của nó trong danh sách giá trị được sắp xếp.

Lợi thế lớn nhất của việc này là bạn có thể xác định tiêu chí sắp xếp khi chạy (ví dụ từ yêu cầu của người dùng).

+0

Đó là loại giải pháp mà tôi đang thử, nhưng tôi nghĩ có lẽ tôi đang làm quá mức nó (mới với Python) và dừng nó lại. Mặc dù nó hơi xấu xí, tôi tin rằng đây là giải pháp hiệu quả. Cảm ơn bạn! –

13

Để khóa của bạn trả về một bộ giá trị số bị từ chối và sau đó là chuỗi. Bằng cách phủ nhận, con số của bạn sẽ được sắp xếp theo thứ tự giảm dần, trong khi các dây đều được sắp xếp theo thứ tự tăng dần:

top_n.sort(key=lambda t: (-t[1], t[0])) 

Vâng, đây là một chút của một hack, nhưng làm việc bất cứ nơi nào bạn cần phải sắp xếp theo hai tiêu chí ở đối diện chỉ đường và một trong các tiêu chí đó là số.

Demo:

>>> top_n = [('Pineapple', 1), ('Orange', 3), ('Banana', 1), ('Apple', 1), ('Cherry', 2)] 
>>> sorted(top_n, key=lambda t: (-t[1], t[0])) 
[('Orange', 3), ('Cherry', 2), ('Apple', 1), ('Banana', 1), ('Pineapple', 1)] 
+1

Vấn đề duy nhất với giải pháp này là việc phủ định chỉ hoạt động với các số nguyên. Tôi không thể đề xuất bất cứ điều gì tốt hơn, giải pháp của tôi là như nhau. – fodma1

+0

Điều gì xảy ra nếu cả hai đối số tuples là chuỗi? – Arman

+3

@Arman: hacking thêm: chuyển đổi chuỗi thành một chuỗi các số nguyên phủ định ('[-chr (c) cho c trong chuỗi]'). –

Các vấn đề liên quan