2010-07-24 1 views
3

мне нужно сортировать следующий список кортежей в Python: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])) 

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

+0

Каковы возможные форматы даты? здесь мы видим «year/monthabbr/day» и «year/monthabbr». Можно ли встретить только «год»? – tokland

+0

Да, это возможно, поскольку формат данных не является регулярным. –

ответ

4
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 будет работать так же хорошо (и гораздо читательнее).

+0

Grazie mille, sei semper gentilissimo! :) Какой подход я должен использовать, чтобы добавить другой ключ заказа, такой как «месяц»? Должен ли я сопоставлять названия месяца с dict ('jan': 1, 'feb: 2')? –

+0

@ Gianluca, используя явный dict, дает вам полный контроль, и поэтому я бы рекомендовал. Вы можете играть с «list (calendar.month_name)», чтобы построить dict, например. в зависимости от языка, но это гораздо сложнее, чем оправданно, если у вас нет особых потребностей в этом направлении. –

+0

Спасибо за ответ :). Прямо сейчас я не могу решить, какой ответ выбрать, потому что также @Duncan опубликовал рабочий подход по моей проблеме. Пока что это вопрос вкуса (Readability vs. Compactness) и производительность (используя «трюки» против «Doing the Python way») ... –

0

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

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')] 
+0

'cmp' больше не работает в Python 3, хотя в functools есть' cmp_to_key'. – kennytm

2

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

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

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

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

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

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

+0

Ваше решение компактно и питонично, но @ Алекс быстрее. Не могу решить, кто победитель :) –

0

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

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) 

«% б» это сокращенное название месяца, вы можете использовать словарь, если вы не хочет иметь дело с локали.

0

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

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

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