Как передать дополнительные аргументы пользовательской функции сортировки Python

Фон:

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

Вот пример, изображающий то, что я хотел бы сделать:

class Book:

      def __init__(self, name, author, language, cost):
          self.name = name
          self.author = author
          self.language=language
          self.cost = cost


bookList = [list of books]

firstLanguage = "Armenian"
possibleLanguages = ["English", "Spanish", "Armenian", "French", "Chinese", "Swahili"]
possibleLanguages.remove("Armenian")

sortedBookList = sorted(bookList, key=(sortByName,
    sortByFirstLanguage(firstLanguage), sortByLanguages(possibleLanguages) ))

По сути, я хотел бы реализовать функции sortByFirstLanguage и sortByLanguages, описанные выше, чтобы я мог передать их функции python 'sorted' в качестве элементов кортежа аргумента 'key'. Вот некоторый пример кода о том, как должны выглядеть пользовательские функции сортировки:

def sortByName(elem):
    return elem.name

def sortByFirstLanguage(elem, firstLanguage):
    if elem.language == firstLanguage:
       return 1
    else:
       return -1


def sortByLanguages(elem, possibleLanguages):
    if elem.language in possibleLanguages:
       return possibleLanguages.index(elem.language)

Доп. Подробности:

  1. Я использую питон 2.7
  2. Эта проблема на самом деле использует наборы запросов Django, а не списки объектов, но для демонстрации цели я думаю, что список объектов служит той же цели.
  3. Целью этой сортировки является сначала сортировка по указанному языку, а затем возврат и сортировка оставшихся элементов по их порядку по умолчанию (в данном случае по списку).

Вопрос:

Как именно я могу сообщить аргументу «ключ» передать дополнительные аргументы «firstLanguage» && «possibleLanguages» пользовательским функциям сортировки, как я показал выше?


person Buck    schedule 27.10.2013    source источник
comment
lambda elem: sortByFirstLanguage(elem, firstLanguage)? Это возьмет elem из элемента, где sorted() вызывает его, и firstLanguage из того места, где он определен.   -  person Sam Mussmann    schedule 28.10.2013
comment
У вас нет надежды пройти их именно таким образом, потому что key работает иначе. key должен принимать функцию (или любую вызываемую функцию), которая вызывается для каждого элемента и возвращает ключ сортировки. Однако вы можете добиться аналогичного эффекта с немного другим дизайном.   -  person BrenBarn    schedule 28.10.2013
comment
что не так с заказом вашего набора запросов с использованием встроенных методов djangos? Что вам нужно sortedBookList для содержания? Список книг, упорядоченных по языку, где определенный язык указан первым?   -  person dm03514    schedule 28.10.2013
comment
Параметр key принимает только 1 функцию, поэтому вам придется написать функцию, выполняющую все 3 типа сортировки.   -  person shad0w_wa1k3r    schedule 28.10.2013


Ответы (1)


Как отмечает Ашиш в комментариях, сначала нам нужно объединить эти функции, поскольку key принимает только одну функцию. Если мы вернем последовательность (список, кортеж) результатов функции, Python сделает все правильно, сравнивая более поздние (крайние справа) элементы, только если более ранние элементы равны (источник).

Я знаю пару способов сделать это.

Использование лямбд:

sortedBookList = sorted(
    bookList, 
    key=lambda elem: (sortByName(elem), 
                      sortByFirstLanguage(elem, firstLanguage), 
                      sortByLanguages(elem, possibleLanguages)))

Использование функций высшего порядка:

def key_combiner(*keyfuncs):
  def helper(elem):
    return [keyfunc(elem) for keyfunc in keyfuncs]
  return helper

def sortByFirstLanguage(firstLanguage):
  def helper(elem):
    return elem.language == firstLanguage  # True > False
  return helper

def sortByLanguages(possibleLanguages):
  def helper(elem):
    if elem.language in possibleLanguages:
       return possibleLanguages.index(elem.language)
  return helper

sortedBookList = sorted(bookList,
                        key=key_combiner(sortByName, 
                                         sortByFirstLanguage(firstLanguage), 
                                         sortByLanguages(possibleLanguages))

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

person Sam Mussmann    schedule 27.10.2013