2013-05-13 34 views
16

Làm cách nào để sắp xếp danh sách các chuỗi theo số key=len trước tiên bằng key=str? Tôi đã thử những điều sau nhưng nó không đem lại cho tôi những loại mong muốn:Cách chỉ định 2 khóa trong python được sắp xếp (danh sách)?

>>> ls = ['foo','bar','foobar','barbar'] 
>>> 
>>> for i in sorted(ls): 
...  print i 
... 
bar 
barbar 
foo 
foobar 
>>> 
>>> for i in sorted(ls, key=len): 
...  print i 
... 
foo 
bar 
foobar 
barbar 
>>> 
>>> for i in sorted(ls, key=str): 
...  print i 
... 
bar 
barbar 
foo 
foobar 

tôi cần phải nhận được:

bar 
foo 
barbar 
foobar 

Trả lời

26

Xác định một chức năng quan trọng mà trả về một tuple trong đó mục đầu tiên là len(str) và cái thứ hai là chính chuỗi đó. Tuples sau đó được so sánh theo từ điển. Tức là, trước tiên các độ dài được so sánh; nếu chúng bằng nhau thì các chuỗi được so sánh.

In [1]: ls = ['foo','bar','foobar','barbar'] 

In [2]: sorted(ls, key=lambda s: (len(s), s)) 
Out[2]: ['bar', 'foo', 'barbar', 'foobar'] 
+0

chỉ 2c nếu hiệu suất quan trọng: một hàm độc lập phải nhanh hơn nhiều so với 'lambda'. – bereal

+0

@root: thật sao? Tại sao? – Eric

+2

@Eric - Duh ... Sau khi thử nghiệm nó - Tôi phải nói rằng thực sự không có bất kỳ sự khác biệt về hiệu suất. – root

2

Nếu bạn không muốn sử dụng lambda:

from operator import itemgetter 
ls = ['foo','bar','foobar','barbar'] 
print sorted([ [x,len(x)] for x in ls ] ,key=itemgetter(1,0)) 
# print [s[0] for s in sorted([ [x,len(x)] for x in ls ] ,key=itemgetter(1,0))] 
+3

Đây là uglier hơn lambda bởi vì bạn đang giới thiệu cruft đến kết quả mà đòi hỏi thêm một '[0]' để truy cập kết quả – jamylak

+0

Có, điều này có thời gian thực hiện x2 so với lambda – perreal

+0

Ngoài ra, đối với tôi thời gian thực hiện với key_function là 1.2 lần phiên bản lambda – perreal

0

Một hình thức mà làm việc mà không có một lambda:

>>> [t[1] for t in sorted((len(s),s) for s in ls)] 
['bar', 'foo', 'barbar', 'foobar'] 
+2

'khóa' đã được tạo nên bạn không cần phải sử dụng DSU – jamylak

12

Câu trả lời từ gốc là đúng, nhưng bạn không thực sự cần số lambda:

>>> def key_function(x): 
     return len(x), str(x) 

>>> sorted(['foo','bar','foobar','barbar'], key=key_function) 
['bar', 'foo', 'barbar', 'foobar'] 

Trong addtion, có một cách tiếp cận thay thế mất lợi thế của sự ổn định phân loại cho phép bạn sắp xếp theo nhiều đèo (với phím thứ cấp đầu tiên):

>>> ls = ['foo','bar','foobar','barbar'] 
>>> ls.sort(key=str)      # secondary key 
>>> ls.sort(key=len)      # primary key 

Xem Sorting HOWTO cho một hướng dẫn tốt về kỹ thuật sắp xếp Python .

+9

Vâng, tôi sẽ nói không cần một chức năng thổi đầy đủ ở đây :) (BTW, bạn có một thiếu', key = key_function) ') – root

+3

Khi phải đối mặt với một câu hỏi mới bắt đầu, tôi thường sẽ không sử dụng một * lambda * trong câu trả lời và thay vào đó sẽ sử dụng công thức đồng nhất nhất của câu trả lời. Nếu ai đó đang đặt câu hỏi này về sắp xếp và các chức năng chính, thì nó gợi ý rằng họ không thoải mái với * lambda *. –

+1

Điểm chụp. Tôi cho rằng tôi đọc nó như là việc sử dụng * lambdas * trong bối cảnh này nên bằng cách nào đó chán nản nói chung. – root

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