Comprensione della funzione della mappa


311
map(function, iterable, ...)

Applica la funzione a ogni elemento di iterabile e restituisce un elenco dei risultati. Se vengono passati altri argomenti iterabili, la funzione deve prendere tanti argomenti e viene applicata agli elementi da tutti gli iterabili in parallelo.

Se un iterabile è più corto di un altro, si presume che sia esteso con Nessuno.

Se la funzione è None, si assume la funzione identità; se sono presenti più argomenti, map()restituisce un elenco composto da tuple contenenti gli elementi corrispondenti da tutti gli iterabili (una sorta di operazione di trasposizione).

Gli argomenti iterabili possono essere una sequenza o qualsiasi oggetto iterabile; il risultato è sempre un elenco.

Che ruolo gioca nella realizzazione di un prodotto cartesiano?

content = map(tuple, array)

Che effetto ha mettere una tupla ovunque lì dentro? Ho anche notato che senza la funzione mappa l'output è abce con esso lo è a, b, c.

Voglio comprendere appieno questa funzione. Anche le definizioni di riferimento sono difficili da capire. Troppa lanugine di fantasia.


2
Cosa vuoi effettivamente ottenere e perché in particolare vuoi usare map?
Kris Harper l'

3
@WebMaster sì, per la prima frase nella documentazione incollata - "Applica la funzione a ogni elemento iterabile". Il resto del paragrafo riguarda casi più complessi, come map(None, a, b, c)risulta da fare zip(a, b, c). Ma molto raramente lo vedi in pratica, proprio perché la zipchiamata è equivalente.
PVC

9
Sto cercando di imparare python e ogni volta che apro una definizione in python.org. dopo la prima frase, non capisco niente. Tutto a posto. grazie.
Web Master l'

2
tupleè una funzione (beh, è ​​più sfumata di così, ma si comporta come una funzione) che prende un iterabile e ti dà una tupla con gli stessi elementi - quindi tuple([1, 2, 3])equivale a (1, 2, 3). Perché map(tuple, array), arraysarebbe un iterabile di iterabili (pensa a un elenco di elenchi) e ti restituirà ogni elenco interno trasformato in una tupla.
PVC

1
In generale, è la prima frase della documentazione di qualsiasi funzione che conta di più. Se lo capisci, ne ottieni l'essenza. Il resto specifica il comportamento in modo molto dettagliato, e alcuni di questi saranno un po 'opachi per cominciare, e potrebbe essere necessario imbattersi in uno strano idioma basato su di esso prima di vedere "oh, questo è ciò che significa!". Ma una volta ottenuto quel momento della lampadina per alcuni builtin, dovresti iniziare a capire i documenti un po 'più facilmente.
PVC

Risposte:


441

mapnon è particolarmente pitonico. Raccomanderei invece di usare la comprensione dell'elenco:

map(f, iterable)

è sostanzialmente equivalente a:

[f(x) for x in iterable]

mapda solo non può fare un prodotto cartesiano, perché la lunghezza della sua lista di output è sempre la stessa della sua lista di input. Puoi banalmente fare un prodotto cartesiano con una comprensione dell'elenco però:

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

La sintassi è un po 'confusa, sostanzialmente equivalente a:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))

36
Trovo che usi mapmolto meno dettagliatamente delle comprensioni dell'elenco, almeno per il caso che stai dimostrando.
Marbel,

1
Come posso usare la mappa per le proprietà? Qual è l' mapequivalente di [v.__name__ for v in (object, str)]?
A Sz

@ASz Che ne dici map(lambda v: v.__name__, list)?
Kilian,

10
la mappa è più veloce poiché non chiama le funzioni in base alla lunghezza degli iteratori .. le funzioni di chiamata hanno un sovraccarico .. Guarda 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati

1
@anati Ho pensato che a voltemap fosse più veloce delle comprensioni, a volte no, proprio a causa del sovraccarico di chiamate di funzione? In particolare, l'euristica che ho appreso è che quando l'utilizzo richiede di introdurre una chiamata di funzione aggiuntiva, le comprensioni sono più veloci? Ad esempio, sono stato portato a credere che sia più lento di , e persino più lento di , proprio a causa della chiamata di funzione aggiuntiva. 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

map non riguarda affatto un prodotto cartesiano, anche se immagino che qualcuno esperto nella programmazione funzionale potrebbe trovare un modo impossibile da capire per generarne uno usando map .

map in Python 3 è equivalente a questo:

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

e l'unica differenza in Python 2 è che creerà un elenco completo di risultati per restituire tutto in una volta invece di yielding.

Sebbene la convenzione Python di solito preferisca le comprensioni (o le espressioni del generatore) per ottenere lo stesso risultato di una chiamata map, in particolare se si utilizza un'espressione lambda come primo argomento:

[func(i) for i in iterable]

Come esempio di ciò che hai chiesto nei commenti sulla domanda: "trasforma una stringa in un array", con "array" probabilmente vorrai una tupla o un elenco (entrambi si comportano un po 'come array di altre lingue) -

 >>> 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 utilizzo di mapquesto sarebbe se inizi con un elenco di stringhe anziché una singola stringa - mappuoi elencarle tutte singolarmente:

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

Nota che map(list, a)è equivalente in Python 2, ma in Python 3 hai bisogno della listchiamata se vuoi fare qualcosa di diverso da inserirlo in un forciclo (o una funzione di elaborazione come sumquella richiede solo un iterabile, e non una sequenza). Ma nota anche che di solito è preferita una comprensione dell'elenco:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

mappa (divertente x -> (x, x)) non sembra difficile da capire ... (anche se ottenere un vero prodotto cartesiano dalla mappa sarebbe impossibile, qualsiasi cosa produca una mappa è sempre una forma di elenco)
Kristopher Micinski

36

map crea un nuovo elenco applicando una funzione a ogni elemento della 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-ary mapequivale a zippare insieme iterabili di input e quindi applicare la funzione di trasformazione su ogni elemento di quell'elenco zippato intermedio. E ' non è un prodotto 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))

Ho usato zip qui, ma il mapcomportamento in realtà differisce leggermente quando gli iterabili non hanno le stesse dimensioni - come notato nella sua documentazione, estende gli iterabili per contenere None.


1
complicato, cercando di digerire questo post
Web Master l'

1
@WebMaster Cosa c'è di complicato?
Jossie Calderon,

La migliore risposta secondo me. L'uso della lambda nell'esempio come funzione lo rende molto chiaro.
sheldonzy,

Sfortunatamente tutti questi non sono equivalenti - l'output è [2,4,6]per la comprensione dell'elenco e i cicli espliciti, ma la mappa restituisce un oggetto mappa - per esempio ottengo questo: <map at 0x123a49978>che poi devo forzare in un elenco.
Leerssej,

20

Semplificando un po ', puoi immaginare di map()fare qualcosa del genere:

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

Come puoi vedere, accetta una funzione e un elenco e restituisce un nuovo elenco con il risultato dell'applicazione della funzione a ciascuno degli elementi nell'elenco di input. Ho detto "semplificando un po '" perché in realtà è map()possibile elaborare più di un iterabile:

Se vengono passati altri argomenti iterabili, la funzione deve prendere tanti argomenti e viene applicata agli elementi da tutti gli iterabili in parallelo. Se un iterabile è più corto di un altro, si presume che sia esteso con Nessuno.

Per la seconda parte della domanda: che ruolo ha questo nella realizzazione di un prodotto cartesiano? beh, map() potrebbe essere usato per generare il prodotto cartesiano di un elenco come questo:

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

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

... Ma a dire la verità, l'utilizzo product()è un modo molto più semplice e naturale per risolvere il problema:

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

In entrambi i casi, il risultato è il prodotto cartesiano lstcome sopra definito:

[(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)]

17

Il map() funzione è lì per applicare la stessa procedura a ogni elemento in una struttura di dati iterabile, come elenchi, generatori, stringhe e altre cose.

Diamo un'occhiata a un esempio: map() può scorrere su ogni elemento in un elenco e applicare una funzione a ciascun elemento, che restituirà (restituendoti) il nuovo elenco.

Immagina di avere una funzione che accetta un numero, aggiunge 1 a quel numero e lo restituisce:

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

Hai anche un elenco di numeri:

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

se si desidera incrementare tutti i numeri nell'elenco, è possibile effettuare le seguenti operazioni:

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

Nota: almeno map() necessari due argomenti. Prima un nome di funzione e poi qualcosa di simile a un elenco.

Vediamo alcune altre cose interessanti che map()possono fare. map()può prendere più iterabili (elenchi, stringhe, ecc.) e passare un elemento da ciascuno iterabile a una funzione come argomento.

Abbiamo tre elenchi:

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

map() può farti un nuovo elenco che contiene l'aggiunta di elementi in un indice specifico.

Ora ricorda map(), ha bisogno di una funzione. Questa volta useremo la sum()funzione integrata. L'esecuzione map()dà il seguente risultato:

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

RICORDA:
In Python 2 map(), eseguirà l'iterazione (passa attraverso gli elementi degli elenchi) in base all'elenco più lungo e passerà Nonealla funzione per gli elenchi più brevi, quindi la tua funzione dovrebbe Nonecercarli e gestirli, altrimenti otterrai errori. In Python 3 map()si fermerà dopo aver terminato con l'elenco più breve. Inoltre, in Python 3, map()restituisce un iteratore, non un elenco.


8

Python3 - map (func, iterable)

Una cosa che non è stata menzionata completamente (sebbene @BlooB l'abbia menzionato) è che la mappa restituisce un oggetto mappa NON un elenco. Questa è una grande differenza quando si tratta di prestazioni temporali su inizializzazione e iterazione. Considera questi due test.

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

Come puoi vedere, l'inizializzazione della funzione mappa non richiede quasi alcun tempo. Tuttavia, iterare attraverso l'oggetto map richiede più tempo del semplice iterare attraverso l'iterabile. Ciò significa che la funzione passata a map () non viene applicata a ciascun elemento finché l'elemento non viene raggiunto nell'iterazione. Se si desidera un elenco, utilizzare la comprensione dell'elenco. Se hai intenzione di scorrere in un ciclo for e ti romperai ad un certo punto, usa la mappa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.