我有一个尝试排序的元组列表,可能需要一些帮助。
我要在元组中排序的字段看起来像“XXX_YYY”。首先,我想以相反的顺序对XXX值进行分组,然后,在这些组中,我想以正常的排序顺序放置YYY值。 (注意:实际上,我也很高兴以这种方式对元组中的第二个项目进行排序,第一个单词为反序,第二个单词为正常序。)
这是我所拥有的以及最终我想要的一个示例……不确定如何去做。
mylist = [
(u'community_news', u'Community: News & Information'),
(u'kf_video', u'KF: Video'),
(u'community_video', u'Community: Video'),
(u'kf_news', u'KF: News & Information'),
(u'kf_magazine', u'KF: Magazine')
]
我想在此列表上执行某种
sort()
,将输出更改为:sorted = [
(u'kf_magazine', u'KF: Magazine'),
(u'kf_news', u'KF: News & Information'),
(u'kf_video', u'KF: Video'),
(u'community_news', u'Community: News & Information'),
(u'community_video', u'Community: Video'),
]
我怀疑可能有Python方式来处理此问题,但无法将我的头缠住它。
最佳答案
正如现有答案中所建议的那样,用于排序的自定义比较功能确实使按升序和降序的排序变得很容易-但它们存在严重的性能问题,在Python 3中已删除,仅保留了首选的自定义方法-自定义键提取函数...速度更快,尽管在混合使用升序/降序的相对罕见的用例中使用起来更精致。
在Python的2.*
中,它支持两种自定义方式(不在同一调用sort
或sorted
:-中同时使用),可以将自定义比较函数作为名为arguments的cmp=
传递。或者,可以将自定义键提取函数作为名为arguments的key=
传递。在Python 3.*
中,仅后一个选项可用。
即使您认为自己只是使用自定义比较方法解决了问题,也绝对值得理解键提取方法:不仅是为了性能,而且还为了将来的适应性(Python 3)和通用性(key=
方法)也适用于min
,max
,itertools.groupby
...比cmp=
方法更通用!)。
当所有键子字段都以相同的方式排序时(所有升序或所有降序),键提取非常简单。如果“相反”的子字段是数字,则仍然很容易(您只需在提取时更改其符号)即可;最好的情况就是您所遇到的情况-必须以相反的方式比较多个字符串字段。
解决您的问题的一种相当简单的方法是一小段补习类:
class Reverser(object):
def __init__(self, s): self.s = s
def __lt__(self, other): return other.s < self.s
def __eq__(self, other): return other.s == self.s
请注意,您只需要提供
__lt__
和__eq__
(<
和==
运算符),就可以根据需要将sort
和好友合成所有其他比较。因此,有了这个小的辅助工具,我们可以轻松进行...:
def getkey(tup):
a, b = tup[0].split('_')
return Reverser(a), b
my_list.sort(key=getkey)
如您所见,一旦“了解”了反向器和键提取概念,使用 key 提取而不是自定义比较就基本上无需付出任何代价:我建议的代码是反向器类的4条语句(您可以编写一次并将其放入您的“糖果袋”模块),三个用于键提取功能,当然一个用于
sort
或sorted
调用-以最紧凑的形式,总共有8个vs自定义比较方法的4 + 1 == 5 (即使用带有符号更改的cmp或带有交换参数的cmp的那个)。三个陈述对于 key 提取的优势来说代价不菲!-)如此短的列表显然不是性能的大问题,而是更长的时间(10倍)……
# my_list as in the Q, my_cmp as per top A, getkey as here
def bycmp():
return sorted(my_list*10, cmp=my_cmp)
def bykey():
return sorted(my_list*10, key=getkey)
...
$ python -mtimeit -s'import so' 'so.bykey()'
1000 loops, best of 3: 548 usec per loop
$ python -mtimeit -s'import so' 'so.bycmp()'
1000 loops, best of 3: 995 usec per loop
也就是说,在处理50个项目列表时,
key=
方法已经显示出将近两倍的性能提升(将列表排序速度提高了两倍),非常值得“8行而不是5行”的适中价格,尤其是对于所有我已经提到的其他优势!