2016-01-14 4 views
6

У меня есть список элементов, которые я хотел бы сортировать по нескольким критериям.Усовершенствованный пользовательский вид

Данный список входов:

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

Критерии:

  • Hm> Ав
  • I> R> H> Е

Вывод должен быть:

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

Я знаю, что эту функцию нужно передать на встроенный sorted(), но любые идеи, как на самом деле написать его?

+0

Возможный дубликат http://stackoverflow.com/questions/14208256/sort-a-list-with-a-custom-order-in-python или http://stackoverflow.com/questions/3624323/питон-хау к обычаю заказ-а-лист – SIslam

ответ

7

Вы могли бы написать функция для ключа, возвращающая 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 

tuple При сортировке с, первые элементы сравниваются в первую очередь. Если они одинаковы, то tuple s сортируются по их вторым элементам и так далее. Это похоже на то, как обычные слова сортируются в алфавитном порядке.

Поскольку мы сначала хотим все элементы с 'I' вместе, то 'R' и так далее, мы положим это первым. Для этого мы определяем словарь, который дает каждой букве свой желаемый приоритет. Когда мы просматриваем эту букву (четвертый символ в строке, s[3]) в этом словаре, есть первая часть ключа.

Далее, мы хотим номер после этой буквы. Для этого мы будем использовать короткое замыкание для получения либо пятого символа, либо вперед (s[4:]), либо, если таковых нет, 0. Мы отправляем его на номер int, который будет оценивать номер в виде номера, чтобы положить '2' после '12', как и должно быть.

И, наконец, если первые две части одинаковы, элементы будут отсортированы на основе их первого символа. Если бы это был более простой вид, мы могли бы просто указать reverse=True. Если бы эта часть была числом, мы могли бы просто принять ее отрицательный результат. Мы просто превратим этот персонаж в число с ord(), а затем возьмем отрицательный результат.

Результатом являются ключи от, например, (0, 2, -65) для 'Aw I2'.

1

Ниже будет работать:

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'] 
1

Для сравнения Aw, Hm и E, H, R, I и т.д. Вы можете определить два словаря:

Теперь нам нужно проанализировать каждую строку на три компонента: 1. (Aw или Hm) 2. (E или H или R или I) 3. Integer

Теперь, используя эти компоненты и соответствующие значения из словаря, мы можем вернуть кортеж из нашей ключевой функции:

>>> 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'] 
1

Давайте что-нибудь создадим:

Как насчет назначения очков вашим письмам?

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)