2013-05-02 80 views
1

希望這將是有意義......排序元組的兩元組條目相反的順序列表

我有以下形式的元組的列表:

list_of_tuples = [('a', 1), ('b', 3), ('b', 2), ('a', 3)] 

所需的輸出是

sorted_list_of_tuples = [('a', 1), ('b', 2), ('b', 3), ('a', 3)] 

問題是我想第二個條目增加,第一個條目要減少。

import operator as op  
sorted_list_of_tuples = sorted(list_of_tuples, key=op.itemgetter(2, 0)) 

這當然會將這兩個字段排序爲增加。我不能拿出一個可愛的(即幾行)來做到這一點。有沒有人有辦法輕鬆完成這種排序?

我似乎記得你可以使用_引用括號內的列表理解元素,所以也許這是一個開始的地方?


也許我不清楚:在這種情況下,整數更重要。它的順序應該越來越大。當一個領帶(即..,第二個條目相等)時,我希望在'a'之前出現'b'。

+0

*我似乎記得您可以使用_引用括號內的列表理解元素,所以也許這是一個開始的地方?* - 我不確定你指的是什麼,但'_'在Python中沒什麼特別的,只是一個變量名。 – 2013-05-02 22:26:00

+0

@Lattyware:我明白。我回憶起來是在這個線程:http://stackoverflow.com/questions/101268/hidden-features-of-python請參閱標題爲「引用一個列表理解,因爲它正在建造......」 – BenDundee 2013-05-02 22:40:58

+0

正如那裏指出,這是一個模糊的實現細節,而不是一般要使用的東西。這裏也沒有真正的相關性。 – 2013-05-02 22:42:54

回答

3

如果你可以用英文描述這個鍵,只需要把它翻譯成一個函數。

我希望第二個條目增加,第一個條目要減少。

所以,關鍵是:

def make_key(my_tuple): 
    return my_tuple[1], -my_tuple[0] 

除,當然,前提是-不起作用的字符串的方式,所以你需要的東西票友。

或者,也許不是......而每個元組的第一個元素是一個字符串,第二個是一個整數,所以,我們就可以否定的關鍵功能,並使用reverse向聯合國人否定它:

def make_key(my_tuple): 
    return -my_tuple[1], my_tuple[0] 

sorted_list_of_tuples = sorted(list_of_tuples, key=make_key, reverse=True) 

如果你想節省一些按鍵:

sorted_list_of_tuples = sorted(list_of_tuples, 
           key=lambda x: (x[1], x[0]), reverse=True) 

這不僅會工作的伎倆 這裏。例如,因爲所有的字符串都是1個字符的字符串,所以ord(x) < ord(y) iff x < y

但有時你不能想到一個簡單的訣竅 - 但你可以想到一個簡單的方法來寫一個比較函數。如果是更可讀的,這樣做的:

def compare_my_tuples(lhs, rhs):   
    if rhs[1] > lhs[0]: return 1 
    elif rhs[1] < lhs[0]: return -1 
    elif rhs[0] > lhs[0]: return -1 
    elif rhs[0] < rhs[0]: return 1 
    else: return 0 

sorted_list_of_tuples = sorted(list_of_tuples, 
           key=functools.cmp_to_key(compare_my_tuples)) 

或者,當然,你可以把它分成兩類,如steveha的答案。 (是的,它可能需要兩倍的時間...但在大多數應用程序中,根本沒有任何區別。)

2

當然。 Python的內置排序是一種「穩定」排序。所以,選擇你想要更重要的那種,並且做一個。做不太重要的事情,然後再用更重要的標準來分類。

工作代碼:

import operator as op 

list_of_tuples = [('a', 1), ('b', 3), ('b', 2), ('a', 3)] 

list_of_tuples.sort(key=op.itemgetter(0), reverse=True) 
list_of_tuples.sort(key=op.itemgetter(1)) 

assert list_of_tuples == [('a', 1), ('b', 2), ('b', 3), ('a', 3)] 

我想你可以做整個事情在一重傳,如果你想出了一個巧妙的按鍵功能。也許這個:

def custom_key_fn(tup): 
    ch, n = tup # unpack tuple 
    return (n, -ord(ch)) 

list_of_tuples = [('a', 1), ('b', 3), ('b', 2), ('a', 3)] 
list_of_tuples.sort(key=custom_key_fn) 

assert list_of_tuples == [('a', 1), ('b', 2), ('b', 3), ('a', 3)] 
+0

你不能用一種排序嗎? – BenDundee 2013-05-02 22:29:03

+0

@BenDundee:當然可以,它只需要一個更復雜的關鍵功能。這是一個折衷。 – abarnert 2013-05-02 22:34:32

+0

我問你的時候我已經在寫了。 :-) – steveha 2013-05-02 22:36:26