web-dev-qa-db-fra.com

Comment utiliser les filtres, mapper et réduire en Python 3

filter, map et reduce fonctionnent parfaitement en Python 2. Voici un exemple:

>>> def f(x):
        return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

>>> def cube(x):
        return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

>>> def add(x,y):
        return x+y
>>> reduce(add, range(1, 11))
55

Mais en Python 3, je reçois les sorties suivantes:

>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>
>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>
>>> reduce(add, range(1, 11))
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    reduce(add, range(1, 11))
NameError: name 'reduce' is not defined

J'apprécierais que quelqu'un puisse m'expliquer pourquoi.

Capture d'écran du code pour plus de clarté:

 IDLE sessions of Python 2 and 3 side-by-side

252
Dick Lucas

Vous pouvez en savoir plus sur les modifications dans Nouveautés de Python 3.0 . Vous devriez le lire attentivement lorsque vous passez de 2.x à 3.x car beaucoup de choses ont été changées.

Toute la réponse ici sont des citations de la documentation.

Vues et itérateurs au lieu de listes

Certaines API connues ne renvoient plus de listes:

  • [...]
  • map() et filter() renvoie les itérateurs. Si vous avez vraiment besoin d'une liste, une solution rapide est par exemple. list(map(...)), mais il est souvent préférable d’utiliser une compréhension de liste (surtout lorsque le code original utilise lambda) ou de réécrire le code afin qu’il n’ait pas besoin de liste. map() est particulièrement délicat appelé pour les effets secondaires de la fonction; la transformation correcte consiste à utiliser une boucle for régulière (car créer une liste ne serait qu'un gaspillage).
  • [...]

Construit

  • [...]
  • _reduce() supprimé. Utilisez functools.reduce() si vous en avez vraiment besoin. Cependant, 99% du temps, une boucle explicite for est plus lisible.
  • [...]
290
nhahtdh

Les fonctionnalités de map et filter ont été intentionnellement modifiées pour renvoyer des itérateurs et la commande de réduction, qui était un élément intégré et placé dans functools.reduce.

Ainsi, pour filter et map, vous pouvez les envelopper avec list() pour voir les résultats comme vous le faisiez auparavant.

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>

Il est maintenant recommandé de remplacer votre utilisation de map et filter par des expressions de générateur ou des compréhensions de liste. Exemple:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>

Ils disent que les boucles for sont 99% plus faciles à lire qu’à réduire, mais je me contenterais de functools.reduce.

Edit: le chiffre de 99% est tiré directement de la page Quoi de neuf en Python 3.0 écrite par Guido van Rossum.

74
Joshua D. Boyd

En tant qu'additif aux autres réponses, cela ressemble à un bon cas d'utilisation pour un gestionnaire de contexte qui remappera les noms de ces fonctions en fonctions renvoyant une liste et introduisant reduce dans l'espace de noms global.

Une implémentation rapide pourrait ressembler à ceci:

from contextlib import contextmanager    

@contextmanager
def noiters(*funcs):
    if not funcs: 
        funcs = [map, filter, Zip] # etc
    from functools import reduce
    globals()[reduce.__name__] = reduce
    for func in funcs:
        globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
    try:
        yield
    finally:
        del globals()[reduce.__name__]
        for func in funcs: globals()[func.__name__] = func

Avec un usage qui ressemble à ceci:

with noiters(map):
    from operator import add
    print(reduce(add, range(1, 20)))
    print(map(int, ['1', '2']))

Quelles impressions:

190
[1, 2]

Juste mes 2 centimes :-)

8

Puisque la méthode reduce a été supprimée de la fonction intégrée de Python3, n'oubliez pas d'importer la functools dans votre code. Veuillez regarder l'extrait de code ci-dessous.

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)
3
Bikash Singh

Voici les exemples de fonctions de filtrage, de mappage et de réduction.

nombres = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]

//Filtre

oddNumbers = list (filtre (lambda x: x% 2! = 0, nombres))

print (oddNumbers)

//Carte

multiplyOf2 = list (map (lambda x: x * 2, nombres))

print (multiplyOf2)

//Réduire

La fonction de réduction, puisqu'elle n'est pas couramment utilisée, a été supprimée des fonctions intégrées à Python 3. Elle est toujours disponible dans le module functools. Vous pouvez ainsi:

de functools importer réduire

sumOfNumbers = réduire (lambda x, y: x + y, nombres)

print (sumOfNumbers)

0
Yogendra Singh