Contactez-nous

Fonctions d'ordre supérieur (map, filter, reduce)

Découvrez les fonctions d'ordre supérieur en Python (map, filter, reduce). Appliquez des fonctions à des séquences, filtrez des éléments et réduisez des séquences à une seule valeur. Maîtrisez la programmation fonctionnelle.

Qu'est-ce qu'une fonction d'ordre supérieur ? Définition et concept

En programmation, une fonction d'ordre supérieur est une fonction qui possède au moins une des caractéristiques suivantes :

  • Elle prend une ou plusieurs fonctions en argument.
  • Elle retourne une fonction comme résultat.

Les fonctions d'ordre supérieur sont un concept clé de la programmation fonctionnelle. Elles permettent de traiter les fonctions comme des valeurs de première classe, c'est-à-dire de les manipuler comme n'importe quelle autre valeur (les affecter à des variables, les passer en argument à d'autres fonctions, les retourner comme résultat).

Python supporte les fonctions d'ordre supérieur. Plusieurs fonctions intégrées sont des fonctions d'ordre supérieur, notamment `map`, `filter`, et `reduce` (bien que `reduce` ne soit plus une fonction intégrée depuis Python 3, elle est disponible dans le module `functools`).

map : appliquer une fonction à chaque élément d'un itérable

La fonction `map` prend deux arguments principaux : une fonction et un itérable (par exemple, une liste, un tuple, ou une chaîne de caractères). Elle applique la fonction à chaque élément de l'itérable et retourne un itérateur qui produit les résultats.

Syntaxe :

map(fonction, itérable)

Exemple : Elever au carré tous les éléments d'une liste

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

# Utilisation de map avec une fonction lambda
carres = map(lambda x: x**2, nombres)

# Conversion de l'itérateur en liste pour afficher les résultats
print(list(carres))  # Affiche [1, 4, 9, 16, 25]

Dans cet exemple, la fonction lambda `lambda x: x**2` est appliquée à chaque élément de la liste `nombres`. `map` retourne un itérateur, que nous convertissons en liste avec `list()` pour afficher les résultats.

Vous pouvez utiliser une fonction nommée au lieu d'une fonction lambda :

def carre(x):
    return x**2

nombres = [1, 2, 3, 4, 5]
carres = map(carre, nombres)
print(list(carres))

`map` peut prendre plusieurs itérables en arguments. Dans ce cas, la fonction doit prendre autant d'arguments qu'il y a d'itérables :

nombres1 = [1, 2, 3]
nombres2 = [4, 5, 6]

sommes = map(lambda x, y: x + y, nombres1, nombres2)
print(list(sommes))  # Affiche [5, 7, 9]

filter : sélectionner les éléments d'un itérable selon un critère

La fonction `filter` prend deux arguments : une fonction et un itérable. Elle applique la fonction à chaque élément de l'itérable et retourne un itérateur qui produit les éléments pour lesquels la fonction retourne `True`.

Syntaxe :

filter(fonction, itérable)

Exemple : Sélectionner les nombres pairs d'une liste

nombres = [1, 2, 3, 4, 5, 6]

# Utilisation de filter avec une fonction lambda
pairs = filter(lambda x: x % 2 == 0, nombres)

# Conversion de l'itérateur en liste pour afficher les résultats
print(list(pairs))  # Affiche [2, 4, 6]

Dans cet exemple, la fonction lambda `lambda x: x % 2 == 0` est appliquée à chaque élément de la liste `nombres`. `filter` retourne un itérateur qui produit uniquement les éléments pour lesquels la fonction lambda retourne `True` (c'est-à-dire les nombres pairs).

Vous pouvez également utiliser une fonction nommée :

def est_pair(x):
    return x % 2 == 0

nombres = [1, 2, 3, 4, 5, 6]
pairs = filter(est_pair, nombres)
print(list(pairs))

reduce : réduire un itérable à une seule valeur (module functools)

La fonction `reduce` prend deux arguments : une fonction et un itérable. Elle applique la fonction de manière cumulative aux éléments de l'itérable, de gauche à droite, de manière à réduire l'itérable à une seule valeur.

Contrairement à `map` et `filter`, `reduce` n'est pas une fonction intégrée en Python 3. Vous devez l'importer depuis le module `functools`.

Syntaxe :

from functools import reduce

reduce(fonction, itérable[, valeur_initiale])
  • `fonction` : Une fonction qui prend deux arguments et retourne une seule valeur.
  • `itérable` : L'itérable à réduire.
  • `valeur_initiale` (optionnel) : Si elle est fournie, elle est utilisée comme premier argument de la fonction. Sinon, les deux premiers éléments de l'itérable sont utilisés.

Exemple : Calculer la somme des éléments d'une liste

from functools import reduce

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

# Utilisation de reduce avec une fonction lambda
somme = reduce(lambda x, y: x + y, nombres)

print(somme)  # Affiche 15 (1 + 2 + 3 + 4 + 5)

Dans cet exemple, la fonction lambda `lambda x, y: x + y` est appliquée de manière cumulative aux éléments de la liste `nombres`. `reduce` commence par appliquer la fonction aux deux premiers éléments (1 et 2), puis applique la fonction au résultat (3) et à l'élément suivant (3), et ainsi de suite, jusqu'à ce qu'il ne reste plus qu'une seule valeur (15).

Exemple avec une valeur initiale :

from functools import reduce

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

somme = reduce(lambda x, y: x + y, nombres, 10) # Commence par 10 + 1, puis 11 + 2 ...

print(somme) # Affiche 25

Vous pouvez aussi utiliser une fonction nommée :

from functools import reduce

def additionner(x, y):
    return x + y

nombres = [1, 2, 3, 4, 5]
somme = reduce(additionner, nombres)
print(somme)

map, filter, reduce vs. compréhensions de listes/générateurs

Dans de nombreux cas, les compréhensions de listes (ou les expressions génératrices) offrent une alternative plus concise et plus lisible à `map`, `filter`, et `reduce`.

Exemples (en reprenant les exemples précédents) :

  • `map` :
nombres = [1, 2, 3, 4, 5]
carres = [x**2 for x in nombres]  # Compréhension de liste équivalente à map(lambda x: x**2, nombres)
  • `filter` :
nombres = [1, 2, 3, 4, 5, 6]
pairs = [x for x in nombres if x % 2 == 0]  # Compréhension de liste équivalente à filter(lambda x: x % 2 == 0, nombres)
  • `reduce` (pour la somme) :
nombres = [1, 2, 3, 4, 5]
somme = sum(nombres)  # La fonction intégrée sum est souvent plus adaptée que reduce pour la somme

En général, il est recommandé d'utiliser les compréhensions de listes (ou les expressions génératrices) plutôt que `map` et `filter` lorsque c'est possible, car elles sont souvent plus lisibles. Pour `reduce`, il est souvent préférable d'utiliser une boucle `for` explicite ou une fonction intégrée (comme `sum`, `min`, `max`, `all`, `any`) si elle existe.

Cependant, `map`, `filter`, et `reduce` restent utiles dans certains cas, notamment lorsque vous avez déjà une fonction nommée que vous voulez appliquer, ou lorsque vous travaillez avec des itérateurs infinis (où les compréhensions de listes ne sont pas possibles).