MAPCAR
Traitement de liste
élément par élément
Moyen mnémotechnique pour mémoriser la fonction (mapcar) :
(Multiple APplications to the Contents of the Address Register)
Cette fonction traite chaque élément d'une liste un par un en un seul appel de la fonction (mapcar).
Syntaxe : | (mapcar fonction liste) |
Arguments : | fonction , une fonction AutoLISP liste une liste (list) |
Valeur retournée : | Une liste (list) |
Avec cette fonction qui exige deux arguments,
on va mettre en premier argument une fonction AutoLISP
et en deuxième argument une liste (list),
puis la fonction (mapcar) va appliquer la fonction en premier argument à tous les éléments de la liste (liste qui est le deuxième argument).
Exemples :
Définition de la liste à traiter : ( setq liste1 '( 10 20 30 40 ))
Lancement de la fonction (mapcar) avec la fonction d'incrémentation (1+) :
( setq liste2 ( mapcar '1+ liste1 ))
Ensuite la variable liste2 contient : (11 21 31 41),
on constate qu'il a bel et bien été ajouté la valeur de 1 à chaque élément de la liste.
Si deux listes sont données en arguments la fonction va traiter séquentiellement chaque élément de chaque liste
Exemple :
Définition des listes de départ :
( setq liste1 '( 1 2 3 ))
( setq liste2 '( 10 20 30 ))
Lancement de la fonction (mapcar) avec la fonction (+) sur les deux listes :
( setq liste3 ( mapcar '+ liste1 liste2 ))
vous remarquez qu'il faut "quoter" le premier argument et donc une autre écriture est possible :
( setq liste3 ( mapcar ( quote +) liste1 liste2 ))
Le contenu de liste3 est donc (11 22 33)
soit le premier élément de liste1 additionné au premier élément de liste2,
puis le deuxième élément de liste1 additionné au deuxième élément de liste2,
et ainsi de suite.
Si les deux listes n'ont pas le même nombre d'éléments,
la fonction s'arrêtera au nombre de paires d'éléments possibles en fonction de la première liste
Exemple avec liste1 qui contient trois éléments et liste2 qui en contient quatre :
( setq liste1 '( 1 2 3 ) liste2 '( 10 20 30 40 ))
Lancement de la fonction (mapcar) avec la fonction (+) sur les deux listes :
( setq liste3 ( mapcar '+ liste1 liste2 ))
et on peut constater que la variable liste3 contient (11 22 33).
la fonction n' a rien additionné à 40 (dernier élément en plus dans liste2) et l'ignore donc
Exemple avec la fonction (cons)
Deux listes au départ, lst1 et lst2 contenant respectivement ( 1 2 3) et (A B C) pour créer une troisième liste ((A . 1) (B . 2) (C . 3)) :
( setq liste1 '(a b c) liste2 '(1 2 3) ) ; fin de setq des listes de départ
( setq liste3 ( mapcar 'cons liste1 liste2 ))
qui renvoie : ((A . 1) (B . 2) (C . 3))
une belle liste de paires pointées (dotted pair) ce qui est le résultat attendu.
Exemple avec la fonction (abs)
Une liste avec des nombres entiers et réels positifs et d'autres négatifs, sans savoir où se trouvent les négatifs dans la liste on veut les transformer en positifs :
( setq liste1 '( 3 -2 5 -9 -5.68 45.12 -0.01 ))
( setq liste1 ( mapcar 'abs liste1 ))
La nouvelle valeur de la variable "liste1" est : (3 2 5 9 5.68 45.12 0.01)
C'est gagné ! il n'y a plus de nombres négatifs et c'est bien ce qu'on voulait obtenir.
Dans cet exemple j'ai choisi d'écraser la liste de départ en lui donnant le même nom suite à l'appel de la fonction (mapcar) mais on peut tout aussi bien créer une nouvelle variable.
Cette efficacité est d'autant plus importante que (mapcar) va gérer tous les éléments de la liste donnée en argument et ce quelque soit le nombre d'élément de cette liste, nombre qu'on a pas besoin de connaître à l'avance.
Encore un exemple assez parlant avec (car)
Le but est de partir d'une liste de coordonnées de points et d'en extraire toutes les valeurs de la coordonnée x (l'abscisse) de tous les points de la liste...
Liste de points :
( setq lst-pts '( (10 11 0) (11 22 0) (12 27 0) ( 13 44 0) (14 37 0) (15 21 0) (16 29 0 0) ))
Cette simple ligne de code : ( mapcar 'car lst-pts )
va renvoyer (10 11 12 13 14 15 16)
qui est la liste de toutes les valeurs de coordonnées X des points (triplets x y z) de la liste donnée en argument, magique, non ?
Et si on voulait incrémenter de un (1+) cette liste des coordonnées x,
par exemple pour déplacer ces points d'une unité de dessin,
le tout en une seule ligne de code...
En reprenant la même liste de points que l'exemple précédent il faudrait taper cette ligne de code avec deux (mapcar) :
( mapcar '1+ ( mapcar 'car lst-pts ))
Ce qui renvoie (11 12 13 14 15 16 17) et là on ne parle plus de magie mais de sorcellerie, non ?
Quand on écrit :
( mapcar '+ '( 1 2 3 ) '( 4 5 6 ) )
On pourrait écrire sans (mapcar) :
( list (+ 1 4 ) (+ 2 5 ) (+ 3 6 ) )
Quand on écrit :
( mapcar '+ ' ( 1 2 3 ) '( 4 5 6 ) '( 7 8 9 ) )
ce qui va renvoyer (12 15 18), parce que 1 + 4 + 7 = 12
et ainsi de suite comme le montre cette décomposition imagée :
On pourrait écrire sans (mapcar) :
( list (+ 1 4 7) (+ 2 5 8) (+ 3 6 9) )
Ou bien encore (toujours sans (mapcar)) :
( list
( + ( car liste1 ) ( car liste2 ) )
( + ( cadr liste1 ) ( cadr liste2 ) )
( + ( caddr liste1 ) ( caddr liste2 ) )
)
Mais ça ne fonctionne que dans le cas de trois listes avec trois "symbol"
Et là on voit bien la puissance de (mapcar) qui n'a aucunement besoin de connaître la longueur de la liste à traiter, non ?
Un des intérêts de cette fonction est que tous les éléments de la liste vont être traités l'un après l'autre, mais aussi que la longueur de la liste à traiter n'a pas à être connue explicitement.
C'est une fonction peu utilisée par les débutants mais qui est très efficace et il faut bien la connaître pour éviter des boucles avec des tests pour traiter des listes.
7 décembre 2017
mise à jour le 23 décembre 2017
mise à jour le 17 juin 2018,
mise à jour le 11 mars 2020
mise à jour le 25 avril 2020
mise à jour le 13 mars 2021