Синтаксис после сортировки (ключ = лямбда:…)

152

Я не совсем понимаю синтаксис sorted()аргумента:

key=lambda variable: variable[0]

Разве не lambdaпроизвольно? Почему variableуказано дважды в том, что выглядит как dict?

Кристофер Маркиета
источник

Ответы:

164

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

Использование lambdaсоздает анонимную функцию (которая вызывается). В случае sortedвызова только принимает один параметр. Python lambdaдовольно прост. Это может только сделать и вернуть одну вещь действительно.

Синтаксис lambda- это слово, lambdaза которым следует список имен параметров, а затем отдельный блок кода. Список параметров и блок кода обозначены двоеточием. Это похоже на другие конструкции в питона , а также такие , как while, for, ifи так далее. Это все операторы, которые обычно имеют блок кода. Лямбда - это просто еще один экземпляр оператора с блоком кода.

Мы можем сравнить использование лямбды с использованием def для создания функции.

adder_lambda = lambda parameter1,parameter2: parameter1+parameter2
def adder_regular(parameter1, parameter2): return parameter1+parameter2

Лямбда просто дает нам способ сделать это без присвоения имени. Что делает его отличным для использования в качестве параметра функции.

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

Evan
источник
11
примечание (к OP): следует избегать присвоения лямбда-имени имени (т. е. использовать его иначе, чем в качестве анонимной функции). если вы обнаружите, что делаете это, вы, вероятно, должны просто использовать def.
Вим
151

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

Для полноты картины я напишу очевидное заранее: sorted () возвращает список отсортированных элементов, и если мы хотим отсортировать определенным образом или если мы хотим отсортировать сложный список элементов (например, вложенные списки или список кортежей) мы можем вызвать ключевой аргумент.

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

  1. В конечном счете, использование lamba означает, что вам не нужно писать (определять) целую функцию, как та, что sblom предоставил в качестве примера. Лямбда-функции создаются, используются и немедленно уничтожаются, поэтому они не наполняют ваш код большим количеством кода, который будет использоваться только один раз. Это, насколько я понимаю, основная утилита лямбда-функции, и ее приложения для таких ролей широки. Его синтаксис является чисто условным, что по сути является природой программного синтаксиса в целом. Изучите синтаксис и покончите с этим.

Лямбда-синтаксис выглядит следующим образом:

лямбда input_variable (s) : вкусный лайнер

например

In [1]: f00 = lambda x: x/2

In [2]: f00(10)
Out[2]: 5.0

In [3]: (lambda x: x/2)(10)
Out[3]: 5.0

In [4]: (lambda x, y: x / y)(10, 2)
Out[4]: 5.0

In [5]: (lambda: 'amazing lambda')() # func with no args!
Out[5]: 'amazing lambda'
  1. Идея, лежащая в основе keyаргумента, состоит в том, что он должен принимать набор инструкций, которые по существу будут указывать функцию sorted () на те элементы списка, которые должны использоваться для сортировки. Когда он говорит key=, что это на самом деле означает: когда я перебираю список по одному элементу за раз (т.е. для e в списке), я собираюсь передать текущий элемент функции, которую я предоставляю в аргументе ключа, и использовать это создать преобразованный список, который будет информировать меня о порядке окончательного отсортированного списка.

Проверьте это:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=WhatToSortBy)

Базовый пример:

sorted(mylist)

[2, 3, 3, 4, 6, 8, 23] # все числа в порядке от малого до большого.

Пример 1:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=lambda x: x%2==0)

[3, 3, 23, 6, 2, 4, 8] # Имеет ли этот отсортированный результат смысл для вас?

Обратите внимание, что моя лямбда-функция сказала sorted, чтобы проверить, была ли (e) четной или нечетной перед сортировкой.

НО ЖДАТЬ! Вы можете (или, возможно, должны) задаться вопросом о двух вещах - во-первых, почему мои шансы наступают раньше, чем мои события (так как мое значение ключа, кажется, говорит моей отсортированной функции расставлять приоритеты для событий с помощью оператора mod в x%2==0). Во-вторых, почему мои вечера вышли из строя? 2 предшествует 6 верно? Анализируя этот результат, мы узнаем кое-что более глубокое о том, как работает аргумент «key» sorted (), особенно в сочетании с анонимной лямбда-функцией.

Во-первых, вы заметите, что в то время как шансы наступают раньше вечера, сами вечера не сортируются. Почему это?? Давайте прочитаем документы :

Ключевые функции Начиная с Python 2.4, функции list.sort () и sorted () добавили ключевой параметр, чтобы указать функцию, которая будет вызываться для каждого элемента списка перед сравнением.

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

Так что же возвращает пример, использующий по модулю? Логическое значение: True == 1, False == 0. Так как же сортировка справляется с этим ключом? Он в основном преобразует исходный список в последовательность 1 и 0.

[3,6,3,2,4,8,23] становится [0,1,0,1,1,1,0]

Теперь мы куда-то добираемся. Что вы получаете, когда сортируете преобразованный список?

[0,0,0,1,1,1,1]

Хорошо, теперь мы знаем, почему шансы наступают раньше вечера. Но следующий вопрос: почему 6 все еще стоят перед 2 в моем окончательном списке? Ну, это легко - это потому, что сортировка происходит только один раз! т.е. эти 1 все еще представляют исходные значения списка, которые находятся в их исходных положениях относительно друг друга. Поскольку сортировка происходит только один раз, и мы не вызываем какую-либо функцию сортировки, чтобы упорядочить исходные четные значения от низкого к высокому, эти значения остаются в своем первоначальном порядке относительно друг друга.

Последний вопрос заключается в следующем: как я концептуально думаю о том, как порядок моих логических значений преобразуется обратно в исходные значения при печати окончательного отсортированного списка?

Sorted () - это встроенный метод, который (забавный факт) использует гибридный алгоритм сортировки под названием Timsort.это объединяет аспекты сортировки слиянием и сортировки вставкой. Мне кажется ясным, что когда вы вызываете его, есть механизм, который хранит эти значения в памяти и связывает их с их логическим тождеством (маской), определяемым (...!) Лямбда-функцией. Порядок определяется их булевой тождественностью, рассчитанной по лямбда-функции, но имейте в виду, что эти подсписки (единиц и нулей) сами по себе не сортируются по их исходным значениям. Следовательно, окончательный список, хотя и упорядоченный по коэффициентам и событиям, не отсортирован по подспискам (в этом случае четные не соответствуют порядку). Тот факт, что шансы упорядочены, объясняется тем, что они уже были в порядке по совпадению в исходном списке. Вывод из всего этого заключается в том, что когда лямбда выполняет это преобразование, первоначальный порядок подсписков сохраняется.

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

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

Давайте попробуем предсказать, что произойдет, когда я запустите следующий код.

mylist = [(3, 5, 8), (6, 2, 8), ( 2, 9, 4), (6, 8, 5)]
sorted(mylist, key=lambda x: x[1])

Мой sortedзвонок явно говорит: «Пожалуйста, сортируйте этот список». Ключевой аргумент делает это немного более конкретным, говоря, что для каждого элемента (x) в mylist возвращают индекс 1 этого элемента, а затем сортируют все элементы исходного списка «mylist» по отсортированному порядку списка, вычисляемому как лямбда-функция. Поскольку у нас есть список кортежей, мы можем вернуть индексированный элемент из этого кортежа. Итак, мы получаем:

[(6, 2, 8), (3, 5, 8), (6, 8, 5), (2, 9, 4)]

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

Это было многословное объяснение, но я надеюсь, что это поможет «разобраться» в вашей интуиции об использовании лямбда-функций в качестве ключевого аргумента в sorted () и выше.

PaulG
источник
8
отличное и исчерпывающее объяснение. Этот ответ заслуживает 100 баллов. Но мне интересно, почему лайки меньше на этот ответ.
Джавед
3
Спасибо за глубокое объяснение. Я читал документы и разбирался с практическими рекомендациями, и мне было непонятно, что стоит за этой keyфункцией. Если вы пытаетесь понять sortedфункцию, их lambdaсинтаксис просто встает на путь понимания.
Санбор
3
Это лучшее объяснение здесь. Это было действительно полезно, чтобы помочь мне понять, как это работает на самом деле - я понял лямбда-функцию, но использовать ее в контексте sorted () не имеет смысла. Это действительно помогло, спасибо!
TGWaffles
2
Это блестящий ответ. Приветствую вас, сэр.
Раджеш Маппу
2
Это один из моих любимых ответов о переполнении стека. Спасибо!
AdR
26

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

>>> (lambda x: x+2)(3)
5
Игнасио Васкес-Абрамс
источник
2
Почему вокруг каждого есть круглые скобки?
Кристофер Маркиета
19
Парень рядом, 3потому что он передается функции. Парень находится вокруг лямбды, поэтому выражение не анализируется как lambda x: x+2(3), что недопустимо, поскольку 2не является функцией.
Игнасио Васкес-Абрамс
Я не уверен, что мне нравится термин «анонимные» функции. Я имею в виду, это правда, что они не названы, поэтому анонимность "технически" точна. Я бы скорее назвал их «временными функциями». Но тогда я педант.
user5179531
12

variableСлева от :этого имя параметра. Использование variableсправа использует параметр.

Значит почти так же, как:

def some_method(variable):
  return variable[0]
sblom
источник
5

Еще один пример использования функции sorted () с key = lambda. Давайте рассмотрим, у вас есть список кортежей. В каждом кортеже у вас есть марка, модель и вес автомобиля, и вы хотите отсортировать этот список кортежей по марке, модели или весу. Вы можете сделать это с помощью лямбды.

cars = [('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000), ('bmw', 'x5', 1700)]

print(sorted(cars, key=lambda car: car[0]))
print(sorted(cars, key=lambda car: car[1]))
print(sorted(cars, key=lambda car: car[2]))

Полученные результаты:

[('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000)]
[('lincoln', 'navigator', 2000), ('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100)]
[('citroen', 'xsara', 1100), ('bmw', 'x5', 1700), ('lincoln', 'navigator', 2000)]
filler36
источник
3

lambdaявляется анонимной функцией, а не произвольной функцией. Принимаемым параметром будет переменная, с которой вы работаете, и столбец, по которому вы его сортируете.

Makoto
источник
1

Просто перефразируя, ключ (Необязательно. Функция, выполняемая для определения порядка. По умолчанию - Нет) в отсортированных функциях ожидает функцию, и вы используете лямбду.

Чтобы определить лямбду, вы указываете свойство объекта, которое хотите отсортировать, и встроенная отсортированная функция python автоматически позаботится об этом.

Если вы хотите отсортировать по нескольким свойствам, тогда присвойте key = lambda x: (property1, property2).

Чтобы указать упорядочение, передайте reverse = true в качестве третьего аргумента (Необязательно. Логическое значение. False отсортирует по возрастанию, True отсортирует по убыванию. По умолчанию False) отсортированной функции.

КТА
источник
1

Простой и не трудоемкий ответ с примером, относящимся к заданному вопросу. Следуйте этому примеру:

 user = [{"name": "Dough", "age": 55}, 
            {"name": "Ben", "age": 44}, 
            {"name": "Citrus", "age": 33},
            {"name": "Abdullah", "age":22},
            ]
    print(sorted(user, key=lambda el: el["name"]))
    print(sorted(user, key= lambda y: y["age"]))

Посмотрите на имена в списке, они начинаются с D, B, C и A. А если вы заметите возраст, это 55, 44, 33 и 22. Первый код для печати

print(sorted(user, key=lambda el: el["name"]))

Результаты к:

[{'name': 'Abdullah', 'age': 22}, 
{'name': 'Ben', 'age': 44}, 
{'name': 'Citrus', 'age': 33}, 
{'name': 'Dough', 'age': 55}]

сортирует имя, потому что по ключу = lambda el: el ["name"] мы сортируем имена, и имена возвращаются в алфавитном порядке.

Второй код печати

print(sorted(user, key= lambda y: y["age"]))

Результат:

[{'name': 'Abdullah', 'age': 22},
 {'name': 'Citrus', 'age': 33},
 {'name': 'Ben', 'age': 44}, 
 {'name': 'Dough', 'age': 55}]

сортирует по возрасту, и, следовательно, список возвращается в порядке возрастания.

Попробуйте этот код для лучшего понимания.

AbdullahS96
источник