2010-11-02 72 views
8

我應該列出單詞並對其進行排序,除了我需要將所有以'x'開頭的字符串分組。寫出這個表達式的更多pythonic方法?

這裏就是我的了:

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) 

但我有一種感覺,有一種更優雅的方式來做到這一點...

編輯

例子: ['mix', 'xyz', 'apple', 'xanadu', 'aardvark']產量['xanadu', 'xyz', 'aardvark', 'apple', 'mix']

回答

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

說明:鍵函數返回一個對(元組)。第一個元素是FalseTrue,具體取決於字符串中的第一個字符是否爲'x'FalseTrue之前排序,因此以'x'開頭的字符串將在排序後的輸出中排第一位。元組中的第二個元素將用於比較第一個元素中相同的兩個元素,因此所有以'x'開頭的字符串將在它們之間排序,並且所有不以'x'開頭的字符串將在它們自己之間排序。

+1

+1,我花了一點時間去理解。 – 2010-11-02 11:57:54

+0

不太明白爲什麼這個工程。真的總是大於x? – helpermethod 2010-11-02 12:06:19

+1

@Helper:它比較元組,它的第一個元素是「False」或「True」。通過這種方式,所有具有「False」的元組作爲第一個元素在所有具有「True」作爲第一個元素的元組之前。當第一個元素相同時,根據第二個元素進行比較,在這種情況下,也是標準字母排序。 – SilentGhost 2010-11-02 12:12:53

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

第一:當你的意思是「乾淨」時停止說「pythonic」。這只是一個俗氣的流行詞。

不要使用那樣的三元表達式;它意味着被用作表達式的一部分,而不是流量控制。這是清潔:

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

可以改善它多一點 - 使用這樣terniary表現是好的:

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

如果words是一個容器,而不是一個迭代器,你可以使用:

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

最後,我們可以放棄整個事情,而是使用兩類:

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

它首先正常排序,然後使用Python的穩定屬性排序,將以「x」開頭的單詞移動到前面,而無需更改排序順序。

+0

順便說一句,雖然它缺少解釋,@SilentGhost的版本更快,更清潔,作爲最終的代碼。 (我更喜歡我的回答,因爲我認爲它更具教育意義,但當然我有偏見。) – 2010-11-02 12:12:34

+7

關於「pythonic」這個詞:這裏有一些有趣的討論:http://nedbatchelder.com/blog/201011/ pythonic.html – 2010-11-03 11:21:31

+1

我認爲三元表達式的使用是完全有效的。甚至可以寫'(list_1 if word [0] =='x'else list_2).append(word)'這個更清楚。 – flow 2010-11-03 14:26:19

2

要重新變化SilenGhosts碼(隨意複製,SilentGhost)作爲代碼不能命令提示符日誌

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

我發現'startswith'和'endswith'在測試一組條件(它們接受元組)時或者當前綴的長度未被預定義時最有用。 – SilentGhost 2010-11-02 16:11:26

+0

好處是我可以在沒有像x或x [0]!='x'這樣的修復的情況下處理,但我不知道它的性能,但是可讀性值得注意......您的解決方案是自動壓縮/解壓縮,口譯員,整潔的東西!可以概括...感謝提醒關於元組點,我已經看到元組使用一個字符串操作,但忘記了哪個! – 2010-11-02 17:02:28

0

沿着你的原始解決方案的線路更多:

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

應當注意在Python 2.4中添加了sorted。如果您想要一個稍微更簡潔的版本,並且稍微向後兼容,則可以使用.sort()的功能,直接使用list還應該注意,在這種情況下(如許多示例所示),使用x[0]樣式數組索引語法時,空字符串將引發異常。.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'] 

唯一的缺點是你要改變給定的對象。這可以通過預先切片清除。

>>> 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'] 
相關問題