代码之家  ›  专栏  ›  技术社区  ›  thornomad

帮助分类:先按这个,然后按那个

  •  5
  • thornomad  · 技术社区  · 15 年前

    我想在元组中排序的字段看起来像“XXX\u 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'), 
    ]
    

    3 回复  |  直到 15 年前
        1
  •  10
  •   Ayman Hourieh    15 年前
    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
    
        2
  •  8
  •   Alex Martelli    15 年前

    习俗 密钥提取 功能。。。速度更快,但对于比较罕见的升序/降序混合排序用例,使用起来更精细。

    用Python 2.* ,它支持任何一种自定义(不是 二者都 同时呼吁 sort sorted :-),自定义比较函数可以作为 cmp= 命名参数;或者,自定义密钥提取函数可以作为 key= 命名参数。用Python 3.*

    理解密钥提取方法绝对是值得的,即使您认为您刚刚用一种定制的比较方法解决了您的问题:不仅是为了性能,而且是为了将来的证明性(Python 3)和通用性( 钥匙= min , max , itertools.groupby ... 远比 化学机械抛光= 接近。

    当所有关键子字段都以相同的方式排序(全部升序或全部降序)时,关键点提取非常简单——您只需提取它们;如果“相反方向”的子字段是数字(您只需在提取时更改它们的符号),这仍然非常容易;微妙的情况正是您所拥有的——多个字符串字段必须以相反的方式进行比较。

    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__ (修订) < == 分类 如果需要的话,朋友们会根据这两者综合所有其他的比较。

    所以,有了这个小辅助工具,我们可以很容易地进行…:

    def getkey(tup):
        a, b = tup[0].split('_')
        return Reverser(a), b
    
    my_list.sort(key=getkey)
    

    如您所见,一旦您“获得”了反向器和密钥提取概念,使用密钥提取而不是自定义比较基本上不需要付出任何代价:我建议的代码是反向器类的4条语句(您可以编写一次并将其放入“goodies bag”模块的某处),密钥提取函数的3条语句,当然还有一个是给 call——与最紧凑形式的自定义比较方法(即使用带符号更改的cmp或带交换参数的cmp)的4+1==5相比,总共8个。三种说法并不能为关键提取的优势付出多大代价

    # 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
    

        3
  •  2
  •   Kylotan    15 年前
    >>> def my_cmp(tuple_1, tuple_2):
        xxx_1, yyy_1 = tuple_1[0].split('_')
        xxx_2, yyy_2 = tuple_2[0].split('_')
        if xxx_1 > xxx_2:
            return -1
        elif xxx_1 < xxx_2:
            return 1
        else:
            return cmp(yyy_1, yyy_2)
    
    
    >>> import pprint
    >>> pprint.pprint(sorted(mylist, my_cmp))
    [(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')]
    

    不是世界上最漂亮的解决方案。。。