Compreendendo a função de mapa

311
map(function, iterable, ...)

Aplique a função a todos os itens iteráveis ​​e retorne uma lista dos resultados. Se argumentos iteráveis ​​adicionais forem passados, a função deverá receber muitos argumentos e será aplicada aos itens de todos os iteráveis ​​em paralelo.

Se um iterável for mais curto que outro, presume-se que seja estendido com nenhum item.

Se a função é None, a função de identidade é assumida; se houver vários argumentos, map()retornará uma lista que consiste em tuplas contendo os itens correspondentes de todas as iteráveis ​​(um tipo de operação de transposição).

Os argumentos iteráveis ​​podem ser uma sequência ou qualquer objeto iterável; o resultado é sempre uma lista.

Que papel isso desempenha na fabricação de um produto cartesiano?

content = map(tuple, array)

Qual o efeito de colocar uma tupla em qualquer lugar? Notei também que, sem a função map, a saída é abce com ela é a, b, c.

Eu quero entender completamente essa função. As definições de referência também são difíceis de entender. Muito buço chique.

Mestre da Web
fonte
2
O que você realmente deseja alcançar e por que especificamente deseja usar map?
Kris Harper
3
@WebMaster sim, de acordo com a primeira frase da documentação que você colou - "Aplicar função a todos os itens iteráveis". O restante do parágrafo trata de casos mais complexos - como map(None, a, b, c)acontece zip(a, b, c). Mas você raramente vê isso na prática, precisamente porque a zipchamada é equivalente.
LVC
9
Estou tentando aprender python e sempre que abro uma definição em python.org. depois da primeira frase, não entendo nada. Tudo bem. obrigado.
Web Master
2
tupleé uma função (bem, é mais sutil do que isso, mas se comporta como uma função) que leva uma iterável e fornece uma tupla com os mesmos elementos - assim tuple([1, 2, 3])é equivalente a (1, 2, 3). Pois map(tuple, array), arrayseria uma iterável das iteráveis ​​(pense em uma lista de listas) e devolve cada lista interna transformada em uma tupla.
LVC
1
Em geral, é a primeira sentença da documentação de qualquer função que mais importa. Se você entende isso, entende a essência. O restante especifica o comportamento em grandes detalhes, e parte disso será um pouco opaco para começar, e talvez você precise encontrar um idioma estranho com base nele antes de ver "oh, é isso que isso significa!". Porém, depois de obter esse momento da lâmpada para alguns componentes internos, comece a entender os documentos um pouco mais facilmente.
LVC

Respostas:

441

mapnão é particularmente pitônico. Eu recomendaria usar a compreensão da lista:

map(f, iterable)

é basicamente equivalente a:

[f(x) for x in iterable]

mappor si só, não pode produzir um produto cartesiano, porque o comprimento de sua lista de saída é sempre o mesmo que sua lista de entrada. Você pode fazer trivialmente um produto cartesiano com uma compreensão da lista:

[(a, b) for a in iterable_a for b in iterable_b]

A sintaxe é um pouco confusa - isso é basicamente equivalente a:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))
Dave
fonte
36
Acho que usar mapmuito menos detalhado do que a compreensão da lista, pelo menos no caso que você está demonstrando.
Marcel
1
Como uso o mapa para propriedades? Qual é o mapequivalente de [v.__name__ for v in (object, str)]?
Um Sz
@ASz Que tal map(lambda v: v.__name__, list)?
Kilian
10
mapa é mais rápido uma vez que não chamar funções com base no comprimento do iterators .. chamar funções tem sobrecarga .. Assista 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
ANATI
1
@anati Pensei que às vezesmap era mais rápido que a compreensão, às vezes não, precisamente por causa da sobrecarga de chamada de função? Em particular, a heurística que aprendi é que, ao usar, é necessário introduzir uma chamada de função extra, as compreensões são mais rápidas? Por exemplo, fui levado a acreditar que é mais lento que , e até mais lento , justamente por causa da chamada de função adicional. mapmap(lambda foo: foo.bar, my_list)foo.bar for foo in my_listmap(operator.add, my_list_of_pairs)x + y for x, y in my_list_of_pairs
Mtraceur
86

mapnão se relaciona com um produto cartesiano, embora eu imagine que alguém bem versado em programação funcional possa inventar uma maneira impossível de entender de gerar um usando map.

map no Python 3 é equivalente a isso:

def map(func, iterable):
    for i in iterable:
        yield func(i)

e a única diferença no Python 2 é que ele criará uma lista completa de resultados para retornar todos de uma vez em vez de yielding.

Embora a convenção Python geralmente prefira as compreensões de lista (ou expressões geradoras) para obter o mesmo resultado que uma chamada map, principalmente se você estiver usando uma expressão lambda como primeiro argumento:

[func(i) for i in iterable]

Como um exemplo do que você pediu nos comentários sobre a pergunta - "transforme uma string em uma matriz", por 'matriz', você provavelmente deseja uma tupla ou uma lista (ambas se comportam um pouco como matrizes de outros idiomas) -

 >>> a = "hello, world"
 >>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')

Um uso mapaqui seria se você começar com uma lista de cadeias em vez de uma única cadeia - mappode listar todas elas individualmente:

>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

Observe que isso map(list, a)é equivalente no Python 2, mas no Python 3 você precisa da listchamada se quiser fazer algo diferente de alimentá-la em um forloop (ou em uma função de processamento como a sumque precisa apenas de uma iterável e não de uma sequência). Mas observe também que geralmente é preferível uma compreensão da lista:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
lvc
fonte
map (divertido x -> (x, x)) não parece difícil de entender ... (embora seria impossível obter um verdadeiro produto cartesiano do mapa, qualquer coisa que o mapa produz é sempre algum tipo de lista)
Kristopher Micinski
36

map cria uma nova lista aplicando uma função a todos os elementos da fonte:

xs = [1, 2, 3]

# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
    ys.append(x * 2)

n-ário mapé equivalente a compactar iteráveis ​​de entrada juntos e, em seguida, aplicar a função de transformação em todos os elementos dessa lista compactada intermediária. É não um produto cartesiano:

xs = [1, 2, 3]
ys = [2, 4, 6]

def f(x, y):
    return (x * 2, y // 2)

# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
    zs.append(f(x, y))

Eu usei zipaqui, mas o mapcomportamento realmente difere um pouco quando as iteráveis ​​não são do mesmo tamanho - conforme observado na documentação, ele estende as iteráveis ​​para conter None.

Cat Plus Plus
fonte
1
complicado, tentando digerir este post
Web Master
1
@WebMaster O que há de complicado nisso?
Jossie Calderon
Melhor resposta na minha opinião. Usar o lambda no exemplo como uma função deixa muito claro.
23418 sheldonzy
Infelizmente todos estes não são equivalentes - a saída é [2,4,6]para a compreensão lista e os loops explícitos, mas o mapa retorna um objeto mapa - por exemplo, fico com esta: <map at 0x123a49978>Que eu, em seguida, deve coagir em uma lista.
Leerssej
20

Simplificando um pouco, você pode imaginar map()fazer algo assim:

def mymap(func, lst):
    result = []
    for e in lst:
        result.append(func(e))
    return result

Como você pode ver, ele pega uma função e uma lista e retorna uma nova lista com o resultado da aplicação da função a cada um dos elementos na lista de entrada. Eu disse "simplificando um pouco" porque, na realidade, map()pode processar mais de um iterável:

Se argumentos iteráveis ​​adicionais forem passados, a função deverá receber muitos argumentos e será aplicada aos itens de todos os iteráveis ​​em paralelo. Se um iterável for mais curto que outro, presume-se que seja estendido com nenhum item.

Para a segunda parte da pergunta: que papel isso desempenha na fabricação de um produto cartesiano? bem, map() poderia ser usado para gerar o produto cartesiano de uma lista como esta:

lst = [1, 2, 3, 4, 5]

from operator import add
reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))

... Mas, para dizer a verdade, usar product()é uma maneira muito mais simples e natural de resolver o problema:

from itertools import product
list(product(lst, lst))

De qualquer maneira, o resultado é o produto cartesiano lstconforme definido acima:

[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 (2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
 (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
 (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]
Óscar López
fonte
17

A map()função existe para aplicar o mesmo procedimento a todos os itens em uma estrutura de dados iterável, como listas, geradores, seqüências de caracteres e outras coisas.

Vejamos um exemplo: map()pode percorrer todos os itens de uma lista e aplicar uma função a cada item, para que retorne (devolva) a nova lista.

Imagine que você tem uma função que pega um número, adiciona 1 a esse número e a retorna:

def add_one(num):
  new_num = num + 1
  return new_num

Você também tem uma lista de números:

my_list = [1, 3, 6, 7, 8, 10]

se você quiser incrementar todos os números da lista, faça o seguinte:

>>> map(add_one, my_list)
[2, 4, 7, 8, 9, 11]

Nota: No mínimo, map()precisa de dois argumentos. Primeiro o nome de uma função e depois algo como uma lista.

Vamos ver outras coisas legais que map()podemos fazer. map()pode pegar vários iterables (listas, seqüências de caracteres etc.) e passar um elemento de cada iterável para uma função como argumento.

Temos três listas:

list_one = [1, 2, 3, 4, 5]
list_two = [11, 12, 13, 14, 15]
list_three = [21, 22, 23, 24, 25]

map() pode fazer de você uma nova lista que contém a adição de elementos em um índice específico.

Agora lembre-se map(), precisa de uma função. Desta vez, usaremos a sum()função incorporada. A corrida map()fornece o seguinte resultado:

>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]

LEMBRE-SE:
No Python 2 map(), iterará (percorrerá os elementos das listas) de acordo com a lista mais longa e passará Nonepara a função pelas listas mais curtas; portanto, sua função deve procurarNone las e manipulá-las, caso contrário, ocorrerá erros. Em Python 3 map()irá parar após terminar com a lista mais curta. Além disso, no Python 3, map()retorna um iterador, não uma lista.

BlooB
fonte
8

Python3 - mapa (func, iterável)

Uma coisa que não foi mencionada completamente (embora o @BlooB tenha mencionado isso) é que o mapa retorna um objeto de mapa, NÃO uma lista. Essa é uma grande diferença quando se trata de desempenho de tempo na inicialização e iteração. Considere estes dois testes.

import time
def test1(iterable):
    a = time.clock()
    map(str, iterable)
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


def test2(iterable):
    a = time.clock()
    [ x for x in map(str, iterable)]
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


test1(range(2000000))  # Prints ~1.7e-5s   ~8s
test2(range(2000000))  # Prints ~9s        ~8s

Como você pode ver, a inicialização da função de mapa quase não leva tempo. No entanto, a iteração no objeto de mapa leva mais tempo do que simplesmente na iterável. Isso significa que a função passada para map () não é aplicada a cada elemento até que o elemento seja atingido na iteração. Se você deseja uma lista, use a compreensão da lista. Se você planeja iterar em um loop for e interromper em algum momento, use map.

Ranga
fonte