2013-05-02 78 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