2015-09-27 6 views
2

Я только начал изучать Python несколько дней назад, и я хотел реализовать свой маленький проект в нем. Мне нужно отсортировать список (string, integer) в порядке убывания по номеру, но в алфавитном порядке, если число одинаково для более чем одного кортежа. Таким образом, у меня есть список, скажем:Пользовательский вид списка кортежей

tuples = [('ggg', 5), ('aaa', 5), ('bbb', 6), ('zzz', 6)] 
tuples.sort(key=lambda score: score[1], reverse=True) 

Это возвращает:

[('bbb', 6), ('zzz', 6), ('ggg', 5), ('aaa', 5)] 

Но то, что я хочу, чтобы это:

[('bbb', 6), ('zzz', 6), ('aaa', 5), ('ggg', 5)] 

В Java я просто реализован компаратор для пользовательского кортеж:

class Pair { 
    public final String s; 
    public final Integer i; 

    public Pair(String s, Integer i) { 
     this.s = s; 
     this.i = i; 
    } 
} 

class PairComparator implements Comparator<Pair> { 

    @Override 
    public int compare(Pair p1, Pair p2) { 
     int c = p1.i.compareTo(p2.i); 
     return (c == 0) ? p1.s.compareTo(p2.s) : c * (-1); 
    } 
} 

Но я ' m не уверен, как это сделать в выражении lambda в Python.

+0

Итак, вы хотите спуститься по номеру и затем подняться по буквам? –

+0

FWIW, Python 2 позволяет использовать собственный параметр функции сравнения для 'sort' (и' max' & 'min'), но в Python 3 он был отключен, поскольку он менее эффективен: функцию пользовательского ключа нужно вызывать только один раз для каждого ключа, но пользовательская функция сравнения вызывается при сравнении _every_. –

+0

Это возможно реализовать пользовательское сравнение в Python 3: создать класс, который реализует методы [rich compare] (https://docs.python.org/3/reference/datamodel.html#object.__lt__). OTOH, встроенный 'sort' (aka Timsort) Python является стабильным, поэтому может быть достаточно просто отсортировать список несколько раз с разными ключами, вместо использования пользовательского сравнения, когда у вас есть сложное требование сортировки. –

ответ

2

Возможно, самый простой способ будет иметь key вернуть кортеж и умножить результат на -1. Например:

>>> tuples.sort(key=lambda x: (-x[1], x[0])) 
>>> tuples 
[('bbb', 6), ('zzz', 6), ('aaa', 5), ('ggg', 5)] 

Это сортирует целые числа в порядке убывания, а затем строки в порядке возрастания.

+0

Я должен был знать, что получу ниндзя, если бы отправил комментарий. :) –

+1

Это случилось со мной больше раз, чем я могу сосчитать :-) –

1

Вы можете просто сортировать на основе отрицательной формы числа и не использовать reverse=True:

>>> >>> tuples.sort(key=lambda x:(-x[1],x[0])) 
>>> tuples 
[('bbb', 6), ('zzz', 6), ('aaa', 5), ('ggg', 5)] 
+1

Если вы не укажете 'x [0]' в ключе _it, будет проигнорировано_, а так как Timsort стабилен, порядок элементов на основе 'x [0]' не изменится. Попробуйте свой код на '[('bbb', 6), ('zzz', 6), ('aaa', 5), ('xxx', 5), ('ggg', 5)]'. –

+0

@ PM2Ring, да, я пропустил «лямбда», спасибо за напоминание. – Kasramvd

0

Другим вариантом является их сортировка дважды с использованием функции модуля оператора operator.itemgetter(). Сначала мы сортируем по первому элементу в порядке возрастания, а затем сортируем по второму элементу в порядке убывания (хотя это менее эффективно).

In [1]: from operator import itemgetter 

In [2]: tuples = [('ggg', 5), ('aaa', 5), ('bbb', 6), ('zzz', 6)] 

In [3]: tuples.sort(key=itemgetter(0)) # [('aaa', 5), ('bbb', 6), ('ggg', 5), ('zzz', 6)] 

In [4]: tuples.sort(key=itemgetter(1), reverse=True) # sort by 2nd element in descending order 

In [5]: tuples 
Out[5]: [('bbb', 6), ('zzz', 6), ('aaa', 5), ('ggg', 5)] 
Смежные вопросы