使用相反顺序的两个元组条目对元组列表进行排序

时间:2013-05-02 22:23:42

标签: python

希望这有意义......

我有以下格式的元组列表:

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))

当然,这会对两个字段进行排序。我无法想出一个可爱的(即几行)方式来做到这一点。有没有人有办法轻松完成这种排序?

我似乎记得你可以使用_在括号内引用列表理解的元素,所以也许这是一个可以开始的地方?


也许我不清楚:在这种情况下整数更重要。它的顺序应该在整个列表中增加。如果有平局(即......,第二个条目相同),我希望'b'出现在'a'之前。

2 个答案:

答案 0 :(得分: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))

或者,当然,你可以把它分成两种,就像史蒂夫的回答一样。 (是的,它可能需要两倍的时间......但在大多数应用程序中,这根本不会产生任何差异。)

答案 1 :(得分: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)]