função python max usando 'key' e expressão lambda

180

Eu venho do fundo OOP e tentando aprender python. Eu estou usando a maxfunção que usa uma expressão lambda para retornar a instância do tipo Playercom o máximo totalScoreentre a lista players.

def winner():
    w = max(players, key=lambda p: p.totalScore)

A função retorna corretamente a instância do tipo Playercom o máximo totalScore. Estou confuso sobre as três coisas a seguir:

  1. Como a maxfunção funciona? Quais são os argumentos que está tomando? Eu olhei para a documentação, mas não entendi.
  2. Qual é o uso da palavra-chave keyna função max? Eu sei que também é usado no contexto da sortfunção
  3. Significado da expressão lambda? Como lê-los? Como eles funcionam?

Todas essas são questões conceituais muito nobres, mas me ajudarão a entender a linguagem. Ajudaria se você pudesse dar exemplos para explicar. obrigado

Vijay
fonte
Qual versão do Python?
CharmlessCoin
2
Você consultou a documentação ?
Inbar Rose
@charmlessCoin python 2.7.5
Vijay
2
@InbarRose Verifiquei a documentação para a função max. Realmente não entendi.
Vijay
10
@InbarRose Agora, esta página é atualmente o principal resultado do Google python max lambdae talvez seja realmente mais útil para novos usuários.
Mark

Respostas:

277

lambda é uma função anônima, é equivalente a:

def func(p):
   return p.totalScore     

Agora maxse torna:

max(players, key=func)

Porém, como defdeclarações são declarações compostas, elas não podem ser usadas onde uma expressão é necessária, é por isso que às vezes lambdasão usadas.

Observe que isso lambdaé equivalente ao que você colocaria em uma declaração de retorno de a def. Portanto, você não pode usar instruções dentro de a lambda, apenas expressões são permitidas.


O que maxfaz?

max (a, b, c, ... [, key = func]) -> valor

Com um único argumento iterável, retorne seu maior item. Com dois ou mais argumentos, retorne o maior argumento.

Portanto, ele simplesmente retorna o objeto que é o maior.


Como keyfunciona?

Por padrão, no Python 2 keycompara itens com base em um conjunto de regras com base no tipo de objetos (por exemplo, uma string é sempre maior que um número inteiro).

Para modificar o objeto antes da comparação ou para comparar com base em um atributo / índice específico, use o keyargumento

Exemplo 1:

Um exemplo simples, suponha que você tenha uma lista de números em forma de sequência, mas deseja comparar esses itens pelo valor inteiro.

>>> lis = ['1', '100', '111', '2']

Aqui, maxos itens são comparados usando seus valores originais (as strings são comparadas lexicograficamente para que você obtenha '2'como saída):

>>> max(lis)
'2'

Para comparar os itens pelo valor inteiro, use keyum simples lambda:

>>> max(lis, key=lambda x:int(x))  # compare `int` version of each item
'111'

Exemplo 2: Aplicando maxa uma lista de tuplas.

>>> lis = [(1,'a'), (3,'c'), (4,'e'), (-1,'z')]

Por padrão max, os itens serão comparados pelo primeiro índice. Se o primeiro índice for o mesmo, ele comparará o segundo índice. Como no meu exemplo, todos os itens têm um primeiro índice exclusivo, então você recebe isso como resposta:

>>> max(lis)
(4, 'e')

Mas e se você quiser comparar cada item pelo valor no índice 1? Simples: use lambda:

>>> max(lis, key = lambda x: x[1])
(-1, 'z')

Comparando itens em um iterável que contém objetos de tipos diferentes :

Lista com itens mistos:

lis = ['1','100','111','2', 2, 2.57]

No Python 2, é possível comparar itens de dois tipos diferentes :

>>> max(lis)  # works in Python 2
'2'
>>> max(lis, key=lambda x: int(x))  # compare integer version of each item
'111'

Mas no Python 3 você não pode mais fazer isso :

>>> lis = ['1', '100', '111', '2', 2, 2.57]
>>> max(lis)
Traceback (most recent call last):
  File "<ipython-input-2-0ce0a02693e4>", line 1, in <module>
    max(lis)
TypeError: unorderable types: int() > str()

Mas isso funciona, pois estamos comparando a versão inteira de cada objeto:

>>> max(lis, key=lambda x: int(x))  # or simply `max(lis, key=int)`
'111'
Ashwini Chaudhary
fonte
Eu acho que isso é antigo, mas eu tinha uma pergunta sobre isso. Vejo para a função lambda, a variável x ou i ou qualquer outra coisa sempre representa o valor nesse índice na lista. Essa iteração é feita pela função max ou pelo lambda? As funções lambda sempre iteram sobre os valores possíveis? Por exemplo: lengths = map(lambda word: len(word), words)onde words=['It', 'is', 'raining', 'cats', 'and', 'dogs']vejo que o lambda está repetindo todas as palavras da lista. Sempre faz isso?
Mo2 10/10
1
@ A iteração Mo2 é feita por maxnot lambda( keyarg é opcional), e durante a iteração, cada item é passado para a função especificada em keye o valor retornado é usado para comparação.
Ashwini Chaudhary 10/10
2
Apenas para as pessoas que vieram aqui pesquisando no Google "max key parameter". max(lis, key=lambda x:int(x))pode ser simplificado como max(lis, key=int). Python tem uma função interna, int (). Da mesma forma, você pode usar outras funções internas como keyargumento. Por exemplo, você pode obter a mais longa seqüência de lis=['a', 'aa', 'aaa']pormax(lis, key=len)
YOUNG
1
@YOUNG Podemos usar qualquer função como argumento chave não apenas builtin funções, a única condição é que a função deve aceitar os itens passados para ele por max, min, sortedetc corretamente. Além disso, mencionei max(lis, key=int)no final. :-)
Ashwini Chaudhary
@ Ashwini Chaudhary .. suponha que eu tenha uma lista como [1,2,3,4,5]. aqui todos os itens são diferentes. Estou usando a função max (set (mylist), key = mylist.count) para encontrar os itens mais frequentes. pois neste caso não há elemento que esteja se repetindo. está retornando o item mais baixo. Podemos fazer algo para que ele retorne zero ou nulo nesse caso.
vikrant rana
12

Versão fortemente simplificada de max:

def max(items, key=lambda x: x):
    current = item[0]
    for item in items:
        if key(item) > key(current):
            current = item
    return current

Em relação ao lambda:

>>> ident = lambda x: x
>>> ident(3)
3
>>> ident(5)
5

>>> times_two = lambda x: 2*x
>>> times_two(2)
4
Markus Unterwaditzer
fonte
10

Como funciona a função max?

Ele procura o item "maior" em um iterável. Eu presumo que você pode procurar o que é isso, mas se não, é algo que você pode fazer um loop, ou seja, uma lista ou string.

Qual é o uso da palavra-chave key na função max? Eu sei que também é usado no contexto da função de classificação

Keyé uma função lambda que informa maxquais objetos no iterável são maiores que outros. Diga se você estava classificando algum objeto que você mesmo criou, e não algo óbvio, como números inteiros.

Significado da expressão lambda? Como lê-los? Como eles funcionam?

Essa é uma pergunta maior. Em termos simples, um lambda é uma função que você pode transmitir e ter outras partes do código que o usam. Veja isso por exemplo:

def sum(a, b, f):
    return (f(a) + f(b))

Isso leva dois objetos, ae b, e uma função f. Ele chama f()cada objeto e os adiciona. Então veja esta chamada:

>>> sum(2, 2, lambda a:  a * 2)
8

sum()pega 2e chama a expressão lambda nela. Então f(a)torna-se 2 * 2, que se torna 4. Em seguida, faz isso be soma os dois.

Em termos não tão simples, as lambdas vêm do cálculo lambda, que é a idéia de uma função que retorna uma função; um conceito matemático muito legal para expressar computação. Você pode ler sobre isso aqui e entendê- lo aqui .

Provavelmente é melhor ler um pouco mais sobre isso, pois as lambdas podem ser confusas e não é imediatamente óbvio o quanto elas são úteis. Confira aqui .

charmlessCoin
fonte
7

maxA função é usada para obter o máximo de um iterable.

Os iteradores podem ser listas, tuplas, objetos de ditado, etc. Ou até objetos personalizados, como no exemplo que você forneceu.

max(iterable[, key=func]) -> value
max(a, b, c, ...[, key=func]) -> value

With a single iterable argument, return its largest item.
With two or more arguments, return the largest argument.

Então, key=funcbasicamente nos permite passar um argumento opcional keypara a função em cuja base o iterador / argumentos fornecidos são classificados e o máximo é retornado.

lambdaé uma palavra-chave python que atua como uma pseudo função. Então, quando você passa um playerobjeto para ele, ele retornará player.totalScore. Assim, o iterável passado para a função maxserá classificado de acordo com o key total de pontuação dos playerobjetos dados e retornará playerquem tiver o máximo totalScore.

Se nenhum keyargumento for fornecido, o máximo será retornado de acordo com as ordens padrão do Python.

Exemplos -

max(1, 3, 5, 7)
>>>7
max([1, 3, 5, 7])
>>>7

people = [('Barack', 'Obama'), ('Oprah', 'Winfrey'), ('Mahatma', 'Gandhi')]
max(people, key=lambda x: x[1])
>>>('Oprah', 'Winfrey')
shad0w_wa1k3r
fonte
6

De acordo com a documentação :

max (iterável [, chave])
max (arg1, arg2, * args [, chave])
Retorna o maior item em um iterável ou o maior de dois ou mais argumentos.

Se um argumento posicional for fornecido, iterável deve ser iterável não vazio (como uma seqüência de caracteres, uma tupla ou uma lista não vazias). O maior item no iterável é retornado. Se dois ou mais argumentos posicionais forem fornecidos, o maior dos argumentos posicionais será retornado.

O argumento opcional key especifica uma função de ordenação de um argumento como a usada para list.sort (). O argumento chave, se fornecido, deve estar no formato de palavra-chave (por exemplo, max (a, b, c, key = func)).

O que isto está dizendo é que, no seu caso, você está fornecendo uma lista, neste caso players. A maxfunção irá percorrer todos os itens da lista e compará-los entre si para obter um "máximo".

Como você pode imaginar, com um objeto complexo como playerdeterminar seu valor para comparação é complicado, então você recebe o keyargumento para determinar como a maxfunção decidirá o valor de cada um player. Nesse caso, você está usando uma função lambda para dizer "para cada um pem playersget p.totalscoree usar isso como seu valor para comparação".

Inbar Rose
fonte
3

maxé uma função incorporada que recebe o primeiro argumento an iterable(como lista ou tupla)

O argumento da palavra-chave keytem seu valor padrão, Nonemas aceita a função para avaliar, considere-o como wrapper que avalia iterável com base na função

Considere este exemplo de dicionário:

d = {'aim':99, 'aid': 45, 'axe': 59, 'big': 9, 'short': 995, 'sin':12, 'sword':1, 'friend':1000, 'artwork':23}

Ex:

>>> max(d.keys())
'sword'

Como você pode ver se você apenas passa o iterável sem kwarg (uma função para key), ele está retornando o valor máximo da chave (em ordem alfabética)

Ex. Em vez de encontrar o valor máximo da chave em ordem alfabética, pode ser necessário encontrar a chave máxima pelo comprimento da chave:

>>>max(d.keys(), key=lambda x: len(x))
'artwork'

Neste exemplo, a função lambda está retornando o comprimento da chave que será iterada, portanto, ao avaliar os valores em vez de considerar alfabeticamente, ela acompanhará o comprimento máximo da chave e retornará a chave que possui o comprimento máximo

Ex.

>>> max(d.keys(), key=lambda x: d[x])
'friend'

neste exemplo, a função lambda está retornando o valor da chave de dicionário correspondente que possui o valor máximo

Gahan
fonte