【问题标题】:Advanced custom sort高级自定义排序
【发布时间】:2016-04-19 17:31:09
【问题描述】:

我有一个项目列表,我想根据多个标准进行排序。

给定输入列表:

cols = [
    'Aw H',
    'Hm I1',
    'Aw I2',
    'Hm R',
    'Aw R',
    'Aw I1',
    'Aw E',
    'Hm I2',
    'Hm H',
    'Hm E',
] 

标准:

  • 嗯>哦
  • I > R > H > E

输出应该是:

cols = [
   'Hm I1',
   'Aw I1',
   'Hm I2',
   'Aw I2',
   'Hm R',
   'Aw R',
   'Hm H',
   'Aw H',
   'Hm E',
   'Aw E'
]

我知道这个函数需要传递给内置的sorted(),但是你知道如何实际编写它吗?

【问题讨论】:

标签: python list python-2.7 sorting


【解决方案1】:

您可以为键编写一个函数,返回一个tuple,每个感兴趣的部分按优先级排序。

def k(s):
    m = {'I':0, 'R':1, 'H':2, 'E':3}
    return m[s[3]], int(s[4:] or 0), -ord(s[0])

cols = [
    'Aw H',
    'Hm I1',
    'Aw I2',
    'Hm R',
    'Aw R',
    'Aw I1',
    'Aw E',
    'Hm I2',
    'Hm H',
    'Hm E',
]

结果:

>>> for i in sorted(cols, key=k):
...     print(i)
...
Hm I1
Aw I1
Hm I2
Aw I2
Hm R
Aw R
Hm H
Aw H
Hm E
Aw E

在对tuples 进行排序时,首先比较第一个元素。如果它们相同,则tuples 按它们的第二个元素排序,依此类推。这类似于普通单词按字母顺序排序的方式。

由于我们首先要将带有'I' 的所有元素放在一起,然后是'R',依此类推,因此我们将其放在首位。为此,我们定义了一个字典,为每个字母赋予其所需的优先级。当我们在字典中查找那个字母(字符串中的第四个字符,s[3])时,就会看到键的第一部分。

接下来,我们想要那个字母后面的数字。为此,我们将使用一些短路来获取第五个字符及以后的字符 (s[4:]),或者,如果没有,则为 0。我们将它发送到int,它会将数字评估为一个数字,并将'2' 放在'12' 之后,就像它应该的那样。

最后,如果前两部分相同,项目将根据它们的第一个字符进行排序。如果这是一个更简单的排序,我们可以指定reverse=True。如果这部分是一个数字,我们可以取它的负数。我们只需将该字符转换为带有ord() 的数字,然后取其负数。

结果是例如(0, 2, -65) 对应'Aw I2' 的键。

【讨论】:

    【解决方案2】:

    以下将起作用:

    cols = [
        'Aw H',
        'Hm I1',
        'Aw I2',
        'Hm R',
        'Aw R',
        'Aw I1',
        'Aw E',
        'Hm I2',
        'Hm H',
        'Hm E',
    ]
    
    def compare(x, y):
        x1, x2 = x.split(' ')
        y1, y2 = y.split(' ')
    
        order = ['I1', 'I2', 'R', 'H', 'E']
    
        if order.index(x2) < order.index(y2):
            return -1
        elif order.index(x2) > order.index(y2):
            return 1
        else:
            if x1 == 'Hm' and y1 == 'Aw':
                return -1
            elif x1 == 'Aw' and y1 == 'Hm':
                return 1
        return 0
    
    cols.sort(compare)
    print(cols)
    

    输出

    ['Hm I1', 'Aw I1', 'Hm I2', 'Aw I2', 'Hm R', 'Aw R', 'Hm H', 'Aw H', 'Hm E', 'Aw E']
    

    【讨论】:

      【解决方案3】:

      为了比较 Aw、Hm 和 E、H、R、I 等,您可以定义两个字典:

      现在我们需要将每个字符串解析为三个部分:1.(Aw 或 Hm)2.(E 或 H 或 R 或​​ I)3 . 整数

      现在使用这些组件和字典中的相应值,我们可以从我们的键函数返回一个元组:

      >>> import re
      >>> from pprint import pprint
      >>> map_1 = {'Aw': 0, 'Hm': 1}
      >>> map_2 = {'E': 0, 'H': 1, 'R': 2, 'I': 3}
      >>> pattern = re.compile(r'(Aw|Hm)\s([EHRI])(\d*)')
      >>> def key_func(x):
          a, b, c = pattern.search(x).groups()
          return map_2[b], -int(c) if c else 0, map_1[a]
      ...
      >>> pprint(sorted(cols, key=key_func, reverse=True))
      ['Hm I1',
       'Aw I1',
       'Hm I2',
       'Aw I2',
       'Hm R',
       'Aw R',
       'Hm H',
       'Aw H',
       'Hm E',
       'Aw E']
      

      【讨论】:

        【解决方案4】:

        让我们创造一些东西:

        给你的信打分怎么样?

        def custom_sort(string):
            value_dict = {'I':400 ,'R': 300,'H': 200,'E':100, 'Hm': 50, 'Aw':40}
            s = string.split()
            points = value_dict[s[0]] + value_dict[s[1][0]]
            if -len(s[1])>1:
                points -= int(s[1][1:])
            return -points
        
        cols = [
            'Aw H',
            'Hm I1',
            'Aw I2',
            'Hm R',
            'Aw R',
            'Aw I1',
            'Aw E',
            'Hm I2',
            'Hm H',
            'Hm E',
        ]
        
        print sorted(cols, key=custom_sort)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-08
          • 1970-01-01
          • 2016-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-16
          • 1970-01-01
          相关资源
          最近更新 更多