2010-11-02 19 views
8

Tôi phải lấy một danh sách các từ và sắp xếp nó, ngoại trừ tôi cần phải nhóm tất cả các chuỗi bắt đầu bằng 'x' trước.Một cách khác nữa để viết biểu thức này?

Đây là những gì tôi nhận:

list_1 = [] 
list_2 = [] 

for word in words: 
    list_1.append(word) if word[0] == 'x' else list_2.append(word) 

return sorted(list_1) + sorted(list_2) 

Nhưng tôi có cảm giác có một cách nhiều thanh lịch hơn để làm điều này ...

EDIT

Ví dụ: ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] sản lượng ['xanadu', 'xyz', 'aardvark', 'apple', 'mix'].

Trả lời

41
>>> words = ['xoo', 'dsd', 'xdd'] 
>>> sorted(words, key=lambda x: (x[0] != 'x', x)) 
['xdd', 'xoo', 'dsd'] 

Giải thích: phím chức năng trả về một cặp (tuple). Phần tử đầu tiên là False hoặc True, tùy thuộc vào việc char đầu tiên trong chuỗi là 'x'. False sắp xếp trước True, do đó, các chuỗi bắt đầu bằng 'x' sẽ là đầu tiên trong đầu ra được sắp xếp. Phần tử thứ hai trong tuple sẽ được sử dụng để so sánh hai phần tử giống nhau trong phần tử đầu tiên, vì vậy tất cả các chuỗi bắt đầu bằng 'x' sẽ được sắp xếp với nhau và tất cả các chuỗi không bắt đầu bằng 'x' sẽ được sắp xếp với nhau.

+1

+1, đã dành cho tôi một chút thời gian để hiểu. –

+0

Không hoàn toàn hiểu tại sao công trình này hoạt động. Là True luôn luôn lớn hơn mà x? – helpermethod

+1

@Helper: nó so sánh tuple, phần tử đầu tiên là 'False' hoặc' True'. Bằng cách này, tất cả các bộ dữ liệu có 'False' là phần tử đầu tiên trước tất cả các bộ dữ liệu có' True' làm phần tử đầu tiên. Khi các yếu tố đầu tiên là như nhau, so sánh được thực hiện dựa trên yếu tố thứ hai, mà là quá nói trong trường hợp này là sắp xếp theo thứ tự chữ cái chuẩn. – SilentGhost

6
words = ['xoo', 'dsd', 'xdd'] 
list1 = [word for word in words if word[0] == 'x'] 
list2 = [word for word in words if word[0] != 'x'] 
2
words = ['xoo', 'dsd', 'xdd'] 
list1=filter(lambda word:word[0]=='x',words) 
list2=filter(lambda word:word[0]!='x',words) 
1
>>> x = ['abc', 'xyz', 'bcd', 'xabc'] 
>>> y = [ele for ele in x if ele.startswith('x')] 
>>> y 
['xyz', 'xabc'] 
>>> z = [ele for ele in x if not ele.startswith('x')] 
>>> z 
['abc', 'bcd'] 
9

Đầu tiên: dừng nói "pythonic" khi bạn muốn nói "sạch". Nó chỉ là một từ thông dụng cheesy.

Không sử dụng các biểu thức terniary như thế; nó có nghĩa là được sử dụng như là một phần của một biểu thức, không phải là điều khiển luồng. Đây là sạch hơn:

for word in words: 
    if word[0] == 'x': 
     list_1.append(word) 
    else: 
     list_2.append(word) 

Bạn có thể cải thiện nó hơn một chút - sử dụng biểu thức terniary như thế này là tốt:

for word in words: 
    target = list_1 if word[0] == 'x' else list_2 
    target.append(word) 

Nếu words là một container và không phải là một iterator, bạn có thể sử dụng:

list_1 = [word for word in words if word[0] == 'x'] 
list_2 = [word for word in words if word[0] != 'x'] 

Cuối cùng, chúng ta có thể loại bỏ toàn bộ điều, và thay vào đó sử dụng hai loại:

result = sorted(words) 
result = sorted(result, key=lambda word: word[0] != 'x') 

lần đầu tiên sắp xếp bình thường, sau đó sử dụng thuộc tính ổn định của các loại Python để di chuyển các từ bắt đầu bằng "x" sang mặt trước mà không thay đổi thứ tự.

+0

Bằng cách này, mặc dù nó thiếu lời giải thích, phiên bản của @ SilentGhost nhanh hơn và sạch hơn như mã cuối cùng. (Tôi thích câu trả lời của tôi bởi vì tôi nghĩ rằng đó là hướng dẫn nhiều hơn, nhưng tất nhiên tôi là thiên vị.) –

+7

Trên từ "pythonic": có một số thảo luận thú vị trong các ý kiến ​​ở đây: http://nedbatchelder.com/blog/201011/ pythonic.html –

+1

tôi nghĩ rằng việc sử dụng biểu thức ternary được trình bày là hoàn toàn hợp lệ. người ta thậm chí có thể viết '(list_1 if word [0] == 'x' else list_2) .append (word)' là rõ ràng hơn. – flow

2

Để gửi lại SilenGhosts biến thể mã (cảm thấy tự do để sao chép, SilentGhost) như mã không command prompt log

notinorder = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark'] 
print sorted(notinorder, key = lambda x: (not x.startswith('x'), x)) 
+0

Tôi thấy rằng 'startswith' và' endswith' hữu ích nhất khi thử nghiệm với một tập hợp các điều kiện (chúng chấp nhận tuple) hoặc khi độ dài của tiền tố không được xác định trước. – SilentGhost

+0

Lợi ích là tôi có thể đối phó với '' mà không sửa lỗi như x hoặc x [0]! = 'X', hiệu năng tôi không biết, nhưng tính khả năng đọc ... Giải pháp của bạn là loại zip/giải nén tự động để sắp xếp theo thông dịch viên, gọn gàng! Có thể khái quát ... Cảm ơn bạn đã nhắc nhở về điểm tuple, tôi đã thấy tuple được sử dụng với một hoạt động chuỗi, nhưng quên đó! –

0

More dọc theo dòng dung dịch ban đầu của bạn:

 
l1=[] 
l2=[] 
for w in sorted(words): 
    (l1 if w[0] == 'x' else l2).append(w) 
l1.extend(l2) 
return l1 
5

Cần lưu ý rằng sorted đã được thêm vào trong Python 2.4. Nếu bạn muốn có một phiên bản ngắn gọn hơn một chút và tương thích ngược hơn một chút, bạn có thể sử dụng chức năng .sort() trực tiếp từ số list.Cũng cần lưu ý rằng các chuỗi rỗng sẽ ném một ngoại lệ khi sử dụng cú pháp lập chỉ mục mảng kiểu dáng x[0] trong trường hợp này (như nhiều ví dụ có)..startswith() should be used instead, as is properly used in Tony Veijalainen's answer.

>>> words = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark'] 
>>> words.sort(key=lambda x: (not x.startswith('x'), x)) 
>>> words 
['xanadu', 'xyz', '', 'aardvark', 'apple', 'mix'] 

Điểm bất lợi duy nhất là bạn đang biến đổi đối tượng đã cho. Điều này có thể được khắc phục bằng cách cắt trước danh sách.

>>> words = ['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark'] 
>>> new_words = words[:] 
>>> new_words.sort(key=lambda x: (not x.startswith('x'), x)) 
>>> new_words 
['xanadu', 'xyz', '', 'aardvark', 'apple', 'mix'] 
>>> words 
['mix', 'xyz', '', 'apple', 'xanadu', 'aardvark'] 
Các vấn đề liên quan