Comprendre la fonction de carte

311
map(function, iterable, ...)

Appliquer la fonction à chaque élément d'itérable et renvoyer une liste des résultats. Si des arguments itérables supplémentaires sont passés, la fonction doit prendre autant d'arguments et est appliquée aux éléments de tous les itérables en parallèle.

Si un itérable est plus court qu'un autre, il est supposé être étendu avec aucun élément.

Si la fonction est None, la fonction d'identité est supposée; s'il y a plusieurs arguments, map()retourne une liste composée de tuples contenant les éléments correspondants de tous les itérables (une sorte d'opération de transposition).

Les arguments itérables peuvent être une séquence ou tout objet itérable; le résultat est toujours une liste.

Quel rôle cela joue-t-il dans la fabrication d'un produit cartésien?

content = map(tuple, array)

Quel effet la mise d'un tuple n'importe où a-t-elle? J'ai également remarqué que sans la fonction de carte, la sortie est abcet avec elle, c'est a, b, c.

Je veux bien comprendre cette fonction. Les définitions de référence sont également difficiles à comprendre. Trop de peluches fantaisie.

Web Master
la source
2
Que voulez-vous réellement réaliser et pourquoi voulez-vous spécifiquement l'utiliser map?
Kris Harper
3
@WebMaster oui, selon la première phrase de la documentation que vous avez collée - "Appliquer la fonction à chaque élément d'itérable". Le reste du paragraphe concerne des cas plus complexes - comme cela map(None, a, b, c)se révèle zip(a, b, c). Mais on le voit très rarement dans la pratique, précisément parce que l' zipappel est équivalent.
lvc
9
Je m'efforce d'apprendre le python et chaque fois que j'ouvre une définition dans python.org. après la première phrase, je ne comprends rien. Bien. Merci.
Web Master
2
tupleest une fonction (enfin, c'est plus nuancé que ça, mais elle se comporte comme une fonction) qui prend un itérable, et vous donne un tuple avec les mêmes éléments - tuple([1, 2, 3])est donc équivalent à (1, 2, 3). Car map(tuple, array), arrayserait un itérable d'itérables (pensez à une liste de listes), et cela vous rend chaque liste intérieure transformée en tuple.
lvc
1
En général, c'est la première phrase de la documentation de toute fonction qui importe le plus. Si vous comprenez cela, vous obtenez l'essentiel. Le reste spécifie le comportement en détail, et certains seront un peu opaques pour commencer, et vous devrez peut-être trouver un idiome étrange basé sur celui-ci avant de voir "oh, c'est ce que cela signifie!". Mais une fois que vous obtenez ce moment d'ampoule pour quelques modules intégrés, vous devriez commencer à comprendre les documents un peu plus facilement.
lvc

Réponses:

442

mapn'est pas particulièrement pythonique. Je recommanderais plutôt d'utiliser des listes de compréhension:

map(f, iterable)

est fondamentalement équivalent à:

[f(x) for x in iterable]

mapà lui seul ne peut pas faire un produit cartésien, car la longueur de sa liste de sortie est toujours la même que sa liste d'entrée. Vous pouvez faire trivialement un produit cartésien avec une compréhension de liste cependant:

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

La syntaxe est un peu déroutante - c'est essentiellement équivalent à:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))
Dave
la source
36
Je trouve l'utilisation mapbeaucoup moins verbeuse que les compréhensions de liste, du moins pour le cas que vous démontrez.
marbel
1
Comment utiliser la carte pour les propriétés? Quel est l' mapéquivalent de [v.__name__ for v in (object, str)]?
Un Sz
@ASz Que diriez-vous map(lambda v: v.__name__, list)?
Kilian
10
carte est plus rapide car il ne nécessite pas de fonctions en fonction de la durée du itérateurs .. appeler des fonctions a en tête .. Regardez 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
Anati
1
@anati Je pensais que mapc'était parfois plus rapide que les compréhensions, parfois non, précisément à cause de la surcharge des appels de fonction? En particulier, l'heuristique que j'ai apprise est que lorsque l'utilisation mapvous oblige à introduire un appel de fonction supplémentaire, les compréhensions sont plus rapides? Par exemple, j'ai été amené à croire que map(lambda foo: foo.bar, my_list)c'est plus lent que foo.bar for foo in my_list, et que c'est même map(operator.add, my_list_of_pairs)plus lent que x + y for x, y in my_list_of_pairs, précisément en raison de l'appel de fonction supplémentaire.
mtraceur
86

mapne se rapporte pas du tout à un produit cartésien, bien que j'imagine qu'une personne connaissant bien la programmation fonctionnelle pourrait trouver une façon impossible de comprendre d'en générer un en utilisant map.

map en Python 3 est équivalent à ceci:

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

et la seule différence dans Python 2 est qu'il va créer une liste complète de résultats à renvoyer tout d'un coup au lieu de yielding.

Bien que la convention Python préfère généralement les listes de compréhension (ou expressions de générateur) pour obtenir le même résultat qu'un appel à map, en particulier si vous utilisez une expression lambda comme premier argument:

[func(i) for i in iterable]

Comme exemple de ce que vous avez demandé dans les commentaires sur la question - «transformer une chaîne en tableau», par «tableau», vous voulez probablement soit un tuple soit une liste (les deux se comportent un peu comme des tableaux provenant d'autres langues) -

 >>> 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')

Une utilisation mapici serait si vous commencez avec une liste de chaînes au lieu d'une seule chaîne - mappouvez les lister toutes individuellement:

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

Notez que map(list, a)c'est équivalent dans Python 2, mais dans Python 3, vous avez besoin de l' listappel si vous voulez faire autre chose que de l'introduire dans une forboucle (ou une fonction de traitement telle que sumcelle-ci n'a besoin que d'un itérable, et non d'une séquence). Mais notez également à nouveau qu'une compréhension de liste est généralement préférée:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
lvc
la source
map (fun x -> (x, x)) ne semble pas difficile à comprendre ... (bien que retirer un vrai produit cartésien de la carte soit impossible, tout ce que la carte produit est toujours une forme de liste)
Kristopher Micinski
36

map crée une nouvelle liste en appliquant une fonction à chaque élément de la source:

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-aire mapéquivaut à compresser ensemble les itérables d'entrée, puis à appliquer la fonction de transformation sur chaque élément de cette liste intermédiaire compressée. Ce n'est pas un produit cartésien:

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))

J'ai utilisé zipici, mais le mapcomportement diffère en fait légèrement lorsque les itérables ne sont pas de la même taille - comme indiqué dans sa documentation, il étend les itérables à contenir None.

Cat Plus Plus
la source
1
compliqué, essayant de digérer ce post
Web Master
1
@WebMaster Qu'est-ce qui est compliqué?
Jossie Calderon
Meilleure réponse à mon avis. L'utilisation du lambda dans l'exemple comme fonction le rend très clair.
sheldonzy
Malheureusement, tous ces éléments ne sont pas équivalents - la sortie [2,4,6]concerne la compréhension de la liste et les boucles explicites, mais la carte renvoie un objet de carte - par exemple, j'obtiens ceci: que <map at 0x123a49978>je dois ensuite contraindre dans une liste.
leerssej
20

Pour simplifier un peu, vous pouvez imaginer map()faire quelque chose comme ceci:

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

Comme vous pouvez le voir, il prend une fonction et une liste, et renvoie une nouvelle liste avec le résultat de l'application de la fonction à chacun des éléments de la liste d'entrée. J'ai dit "simplifier un peu" car en réalité map()on peut traiter plus d'un itérable:

Si des arguments itérables supplémentaires sont passés, la fonction doit prendre autant d'arguments et est appliquée aux éléments de tous les itérables en parallèle. Si un itérable est plus court qu'un autre, il est supposé être étendu avec aucun élément.

Pour la deuxième partie de la question: quel rôle cela joue-t-il dans la fabrication d'un produit cartésien? bien, map() pourrait être utilisé pour générer le produit cartésien d'une liste comme ceci:

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

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

... Mais à vrai dire, l'utilisation product()est un moyen beaucoup plus simple et naturel de résoudre le problème:

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

Quoi qu'il en soit, le résultat est le produit cartésien de la lstmanière définie ci-dessus:

[(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
la source
17

La map()fonction est là pour appliquer la même procédure à chaque élément d'une structure de données itérable, comme les listes, les générateurs, les chaînes et autres éléments.

Regardons un exemple: map()peut parcourir chaque élément d'une liste et appliquer une fonction à chaque élément, puis il retournera (vous rendra) la nouvelle liste.

Imaginez que vous ayez une fonction qui prend un nombre, ajoute 1 à ce nombre et le renvoie:

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

Vous avez également une liste de numéros:

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

si vous souhaitez incrémenter chaque numéro de la liste, vous pouvez procéder comme suit:

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

Remarque: map()nécessite au minimum deux arguments. D'abord un nom de fonction et ensuite quelque chose comme une liste.

Voyons voir d'autres choses sympas qui map()peuvent faire. map()peut prendre plusieurs itérables (listes, chaînes, etc.) et passer un élément de chaque itérable à une fonction comme argument.

Nous avons trois listes:

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

map() peut vous faire une nouvelle liste qui contient l'ajout d'éléments à un index spécifique.

Rappelez map()- vous maintenant , a besoin d'une fonction. Cette fois, nous utiliserons la sum()fonction intégrée . La course map()donne le résultat suivant:

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

RAPPELEZ-VOUS:
En Python 2 map(), itérera (parcourra les éléments des listes) en fonction de la liste la plus longue, et passera Noneà la fonction pour les listes plus courtes, donc votre fonction devrait les rechercher Noneet les gérer, sinon vous obtiendrez des erreurs. En Python 3 map()s'arrêtera après avoir terminé avec la liste la plus courte. De plus, en Python 3, map()renvoie un itérateur, pas une liste.

BlooB
la source
8

Python3 - carte (func, itérable)

Une chose qui n'a pas été complètement mentionnée (bien que @BlooB l'ait un peu mentionné) est que map retourne un objet map PAS une liste. C'est une grande différence en ce qui concerne les performances temporelles lors de l'initialisation et de l'itération. Considérez ces deux tests.

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

Comme vous pouvez le voir, l'initialisation de la fonction de carte ne prend presque pas de temps. Cependant, l'itération à travers l'objet de carte prend plus de temps que la simple itération à travers l'itérable. Cela signifie que la fonction passée à map () n'est pas appliquée à chaque élément tant que l'élément n'est pas atteint dans l'itération. Si vous voulez une liste, utilisez la compréhension de liste. Si vous prévoyez de parcourir une boucle for et que vous vous interrompez à un moment donné, utilisez la carte.

Ranga
la source