Вопрос сортировки Python - PullRequest
3 голосов
/ 24 июля 2010

Мне нужно отсортировать следующий список кортежей в Python:

ListOfTuples = [('10', '2010 Jan 1;', 'Rapoport AM', 'Role of antiepileptic drugs as preventive agents for migraine', '20030417'), ('21', '2009 Nov;', 'Johannessen SI', 'Antiepilepticdrugs in epilepsy and other disorders--a population-based study of prescriptions', '19679449'),...]

Моя цель - заказать его по По убыванию год (listOfTuples [2]) и По возрастанию Автор (listOfTuples [2]):

sorted(result, key = lambda item: (item[1], item[2]))

Но это не работает. Как я могу получить стабильность сортировки?

Ответы [ 5 ]

4 голосов
/ 24 июля 2010
def descyear_ascauth(atup):
  datestr = atup[1]
  authstr = atup[2]
  year = int(datestr.split(None, 1)[0])
  return -year, authstr

... sorted(result, key=descyear_ascauth) ...

Примечания: вам нужно извлечь год как целое число (не как строку), чтобы вы могли изменить его знак - последний быть ключевым трюком для удовлетворения «нисходящей» части спецификаций. Сжать все это в пределах lambda было бы возможно, но нет абсолютно никакой причины делать это и жертвовать еще большей читабельностью, когда def будет работать так же хорошо (и гораздо более читабельно).

2 голосов
/ 24 июля 2010

Самый простой способ - отсортировать по каждому значению ключа отдельно. Начните с наименее значимого ключа и пройдите до самого значимого.

Так что в этом случае:

import operator
ListOfTuples.sort(key=operator.itemgetter(2))
ListOfTuples.sort(key=lambda x: x[1][:4], reverse=True)

Это работает, потому что сортировка Python всегда стабильна, даже если вы используете флаг реверса: т. Е. Реверс не просто сортирует, а затем реверсирует (что может привести к потере стабильности, он сохраняет стабильность после реверса.

Конечно, если у вас много ключевых столбцов, это может быть неэффективно, поскольку выполняет полную сортировку несколько раз.

Вам не нужно преобразовывать год в число таким образом, поскольку это настоящая обратная сортировка, хотя вы могли бы, если хотите.

0 голосов
/ 25 июля 2010

Вот лямбда-версия ответа Алекса. Я думаю, что теперь он выглядит более компактным, чем ответ Дункана, но очевидно, что большая часть читабельности ответа Алекса была потеряна.

sorted(ListOfTuples, key=lambda atup: (-int(atup[1].split(None, 1)[0]), atup[2]))

Читаемость и эффективность обычно предпочтительнее компактности.

0 голосов
/ 24 июля 2010

Вот примерное решение, которое включает в себя сокращение месяца и день (если найден) в учете:

import time
import operator

def sortkey(seq):
    strdate, author = seq[1], seq[2]
    spdate = strdate[:-1].split()
    month = time.strptime(spdate[1], "%b").tm_mon
    date = [int(spdate[0]), month] + map(int, spdate[2:])
    return map(operator.neg, date), author  

print sorted(result, key=sortkey)

"% b" - это сокращенное название месяца, если вы предпочитаете не иметь дело с языками, вы можете использовать словарь.

0 голосов
/ 24 июля 2010

Вот идиома, которая работает для всего, даже для вещей, которые нельзя отрицать, например, для строк:

data = [ ('a', 'a'), ('a', 'b'), ('b','a') ]

def sort_func( a, b ):
    # compare tuples with the 2nd entry switched
    # this inverts the sorting on the 2nd entry
    return cmp( (a[0], b[1]), (b[0], a[1]) ) 

print sorted( data )                    # [('a', 'a'), ('a', 'b'), ('b', 'a')]
print sorted( data, cmp=sort_func )     # [('a', 'b'), ('a', 'a'), ('b', 'a')]
...