我有一个我想要排序的元组列表,可以使用一些帮助.
我想在元组中排序的字段看起来像"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')
]
Run Code Online (Sandbox Code Playgroud)
我想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'),
]
Run Code Online (Sandbox Code Playgroud)
我怀疑可能有一种pythonic方式来处理这个问题,但我无法绕过它.
Aym*_*ieh 10
def my_cmp(x, y):
x1, x2 = x[0].split('_')
y1, y2 = y[0].split('_')
return -cmp(x1, y1) or cmp(x2, y2)
my_list = [
(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')
]
sorted_list = [
(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'),
]
my_list.sort(cmp=my_cmp)
assert my_list == sorted_list
Run Code Online (Sandbox Code Playgroud)
用于排序的自定义比较函数,如现有答案所示,确实可以轻松地按升序和降序排序 - 但它们存在严重的性能问题,并且已在Python 3中删除,只留下首选的自定义方法 -自定义密钥提取功能......更加快速,但对于相对罕见的混合上升/下降排序用例更加精巧.
在Python 2.*,它支持任一类型的自定义的(未都在相同的呼叫sort或sorted:-),自定义比较功能可以作为一个被传递cmp=命名参数; 或者,自定义键提取函数可以作为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
Run Code Online (Sandbox Code Playgroud)
请注意,您只需要提供__lt__和__eq__(<和==运算符) - sort并且如果需要,朋友可以根据这两个进行综合所有其他比较.
所以,有了这个小辅助工具,我们可以轻松地进行......:
def getkey(tup):
a, b = tup[0].split('_')
return Reverser(a), b
my_list.sort(key=getkey)
Run Code Online (Sandbox Code Playgroud)
如你所见,一旦你"获得"反向器和密钥提取概念,你基本上没有为使用密钥提取而不是自定义比较付出代价:我建议的代码是反向器类的4个语句(你可以写一次并放入你的"好东西包"模块在哪里),三个用于密钥提取功能,当然一个用于sort或sorted调用 - 总共八个与4 + 1 == 5的自定义比较方法以最紧凑的形式(即使用带有符号更改的cmp或带有交换参数的cmp的那个.三个陈述对于密钥提取的优势来说并不是很重要! - )
对于如此短的清单,性能显然不是一个大问题,但是平均时间稍长(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
Run Code Online (Sandbox Code Playgroud)
也就是说,key=当处理50个项目列表时,该方法已经显示出几乎两倍的性能提升(将列表排序两倍的速度) - 非常值得"8行而不是5"的适度价格,特别是所有的我已经提到的其他优点!