帮助排序:首先由此,然后由此

tho*_*mad 5 python sorting

我有一个我想要排序的元组列表,可以使用一些帮助.

我想在元组中排序的字段看起来像"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)


Ale*_*lli 8

用于排序的自定义比较函数,如现有答案所示,确实可以轻松地按升序和降序排序 - 但它们存在严重的性能问题,并且已在Python 3中删除,只留下首选的自定义方法 -自定义密钥提取功能......更加快速,但对于相对罕见的混合上升/下降排序用例更加精巧.

在Python 2.*,它支持任一类型的自定义的(未在相同的呼叫sortsorted:-),自定义比较功能可以作为一个被传递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个语句(你可以写一次并放入你的"好东西包"模块在哪里),三个用于密钥提取功能,当然一个用于sortsorted调用 - 总共八个与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"的适度价格,特别是所有的我已经提到的其他优点!

  • @Alex:我犹豫要编辑*你的*答案中的一个但是my_list.key(cmp = my_cmp)可能应该是my_list.sort(key = getkey)? (2认同)