Comprender la función del mapa

311
map(function, iterable, ...)

Aplique la función a cada elemento de iterable y devuelva una lista de los resultados. Si se pasan argumentos iterables adicionales, la función debe tomar esa cantidad de argumentos y se aplica a los elementos de todos los iterables en paralelo.

Si un iterable es más corto que otro, se supone que se extiende con ninguno de los elementos.

Si la función es None, se asume la función de identidad; si hay varios argumentos, map()devuelve una lista que consta de tuplas que contienen los elementos correspondientes de todos los iterables (un tipo de operación de transposición).

Los argumentos iterables pueden ser una secuencia o cualquier objeto iterable; El resultado es siempre una lista.

¿Qué papel juega esto en la fabricación de un producto cartesiano?

content = map(tuple, array)

¿Qué efecto tiene poner una tupla en cualquier lugar? También noté que sin la función de mapa la salida es abcy con ella, es a, b, c.

Quiero entender completamente esta función. Las definiciones de referencia también son difíciles de entender. Demasiada pelusa elegante.

Administrador de página web
fuente
2
¿Qué es lo que realmente quieres lograr y por qué específicamente quieres usarlo map?
Kris Harper
3
@WebMaster sí, según la primera oración de la documentación que pegó: "Aplicar función a cada elemento de iterable". El resto del párrafo trata sobre casos más complejos, como map(None, a, b, c)resulta ser zip(a, b, c). Pero rara vez se ve eso en la práctica, precisamente porque la zipllamada es equivalente.
lvc
99
Estoy tratando de aprender Python y cada vez que abro una definición en python.org. después de la primera oración, no entiendo nada. Bien. gracias.
Web Master
2
tuplees una función (bueno, tiene más matices que eso, pero se comporta como una función) que toma una iteración y le da una tupla con los mismos elementos, por lo que tuple([1, 2, 3])es equivalente a (1, 2, 3). Para map(tuple, array), arraysería un iterable de iterables (piense en una lista de listas), y le devuelve cada lista interna convertida en una tupla.
lvc
1
En general, es la primera oración de la documentación de cualquier función que más importa. Si entiendes eso, entiendes lo esencial. El resto especifica el comportamiento con gran detalle, y algo de eso será un poco opaco para empezar, y es posible que tengas que encontrar un idioma extraño basado en él antes de que veas "¡oh, eso es lo que eso significa!". Pero una vez que tenga ese momento de bombilla por unos pocos días, debería comenzar a poder entender los documentos un poco más fácilmente.
lvc

Respuestas:

441

mapNo es particularmente pitónico. En su lugar, recomendaría usar comprensiones de listas:

map(f, iterable)

es básicamente equivalente a:

[f(x) for x in iterable]

mappor sí solo no puede hacer un producto cartesiano, porque la longitud de su lista de salida es siempre la misma que su lista de entrada. Sin embargo, puede hacer trivialmente un producto cartesiano con una comprensión de la lista:

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

La sintaxis es un poco confusa, eso es básicamente equivalente a:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))
Dave
fuente
36
Encuentro que uso mapmucho menos detallado que las comprensiones de listas, al menos para el caso que está demostrando.
marbel
1
¿Cómo uso el mapa para propiedades? ¿Cuál es el mapequivalente de [v.__name__ for v in (object, str)]?
Un Sz
@ASz ¿Qué tal map(lambda v: v.__name__, list)?
Kilian
10
El mapa es más rápido ya que no llama a las funciones en función de la longitud de los iteradores. Las funciones de llamada tienen sobrecarga. Mira las 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati el
1
@anati pensé que a vecesmap era más rápido que las comprensiones, a veces no, ¿precisamente por la sobrecarga de llamadas a funciones? En particular, la heurística que aprendí es que cuando usas requiere que introduzcas una llamada de función adicional, ¿la comprensión es más rápida? Por ejemplo, me hicieron creer que es más lento que , y que incluso es más lento que , precisamente debido a la llamada de función 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

mapno se relaciona en absoluto con un producto cartesiano, aunque imagino que alguien bien versado en programación funcional podría encontrar alguna forma imposible de entender para generar uno usando map.

map en Python 3 es equivalente a esto:

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

y la única diferencia en Python 2 es que creará una lista completa de resultados para devolverlos todos a la vez en lugar de yielding.

Aunque la convención de Python generalmente prefiere las comprensiones de listas (o expresiones generadoras) para lograr el mismo resultado que una llamada map, particularmente si está utilizando una expresión lambda como primer argumento:

[func(i) for i in iterable]

Como ejemplo de lo que solicitó en los comentarios sobre la pregunta: "convierta una cadena en una matriz", por 'matriz' probablemente desee una tupla o una lista (ambas se comportan un poco como matrices de otros 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')

Un uso de mapaquí sería si comienza con una lista de cadenas en lugar de una sola cadena; mappuede enumerarlas todas individualmente:

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

Tenga en cuenta que eso map(list, a)es equivalente en Python 2, pero en Python 3 necesita la listllamada si desea hacer algo más que alimentarlo en un forbucle (o una función de procesamiento como sumesa solo necesita un iterable, y no una secuencia). Pero también tenga en cuenta nuevamente que generalmente se prefiere una comprensión de la lista:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
lvc
fuente
map (diversión x -> (x, x)) no parece difícil de entender ... (aunque sería imposible sacar un verdadero producto cartesiano del mapa, todo lo que map produce siempre es una lista)
Kristopher Micinski
36

map crea una nueva lista aplicando una función a cada elemento de la fuente:

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-ary mapes equivalente a comprimir los iterables de entrada juntos y luego aplicar la función de transformación en cada elemento de esa lista comprimida intermedia. Es no un producto 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))

Lo he usado zipaquí, pero el mapcomportamiento en realidad difiere ligeramente cuando los iterables no son del mismo tamaño, como se señala en su documentación, se extiende para contenerlos None.

Cat Plus Plus
fuente
1
complicado, tratando de digerir esta publicación
Web Master
1
@WebMaster ¿Qué tiene de complicado?
Jossie Calderon
La mejor respuesta en mi opinión. Usar la lambda en el ejemplo como una función lo deja muy claro.
sheldonzy
Desafortunadamente, todo esto no es equivalente: el resultado es [2,4,6]para la comprensión de la lista y los bucles explícitos, pero el mapa devuelve un objeto de mapa; por ejemplo, obtengo esto: <map at 0x123a49978>que luego debo forzar en una lista.
leerssej
20

Simplificando un poco, puedes imaginar map()hacer algo como esto:

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

Como puede ver, toma una función y una lista, y devuelve una nueva lista con el resultado de aplicar la función a cada uno de los elementos en la lista de entrada. Dije "simplificar un poco" porque en realidad map()puede procesar más de un iterable:

Si se pasan argumentos iterables adicionales, la función debe tomar esa cantidad de argumentos y se aplica a los elementos de todos los iterables en paralelo. Si un iterable es más corto que otro, se supone que se extiende con ninguno de los elementos.

Para la segunda parte de la pregunta: ¿Qué papel juega esto en la fabricación de un producto cartesiano? bueno, map() podría usarse para generar el producto cartesiano de una 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))

... Pero a decir verdad, usar product()es una forma mucho más simple y natural de resolver el problema:

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

De cualquier manera, el resultado es el producto cartesiano de lstcomo se definió anteriormente:

[(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
fuente
17

La map()función está ahí para aplicar el mismo procedimiento a cada elemento en una estructura de datos iterable, como listas, generadores, cadenas y otras cosas.

Veamos un ejemplo: map()puede iterar sobre cada elemento de una lista y aplicar una función a cada elemento, de lo que devolverá (devolverá) la nueva lista.

Imagine que tiene una función que toma un número, agrega 1 a ese número y lo devuelve:

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

También tienes una lista de números:

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

Si desea incrementar cada número de la lista, puede hacer lo siguiente:

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

Nota: Como mínimo map()necesita dos argumentos. Primero un nombre de función y segundo algo así como una lista.

Veamos algunas otras cosas geniales que map()pueden hacer. map()puede tomar múltiples iterables (listas, cadenas, etc.) y pasar un elemento de cada iterable a una función como argumento.

Tenemos tres listas:

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

map() puede crear una nueva lista que contenga la adición de elementos en un índice específico.

Ahora recuerda map(), necesita una función. Esta vez usaremos la sum()función incorporada . Correr map()da el siguiente resultado:

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

RECUERDE:
En Python 2 map(), iterará (recorrerá los elementos de las listas) de acuerdo con la lista más larga y pasará Nonea la función para las listas más cortas, por lo que su función debe buscarlas Noney manejarlas, de lo contrario obtendrá errores. En Python 3 map()se detendrá después de terminar con la lista más corta. Además, en Python 3, map()devuelve un iterador, no una lista.

BlooB
fuente
8

Python3 - mapa (func, iterable)

Una cosa que no se mencionó por completo (aunque @BlooB lo mencionó un poco) es que el mapa devuelve un objeto de mapa NO una lista. Esta es una gran diferencia cuando se trata del rendimiento de tiempo en la inicialización y la iteración. Considere estas dos pruebas.

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 puede ver, la inicialización de la función de mapa no requiere casi nada de tiempo. Sin embargo, recorrer el objeto del mapa lleva más tiempo que simplemente recorrer el iterable. Esto significa que la función pasada a map () no se aplica a cada elemento hasta que se alcanza el elemento en la iteración. Si desea una lista, use la comprensión de la lista. Si planea iterar en un bucle for y se romperá en algún momento, use map.

Ranga
fuente