Python >> Tutoriel Python >  >> Python

Python :mapper une fonction sur des itérables récursifs

Nous analysons chaque élément de la séquence et procédons à une récursivité plus profonde si l'élément actuel est une sous-séquence, ou produisons son mappage si nous avons atteint un type de données non séquentiel (peut être int , str , ou toute classe complexe).

Nous utilisons collections.Sequence pour généraliser l'idée pour chaque séquence, et pas seulement pour les tuples ou les listes, et type(item) lors du rendement pour s'assurer que les sous-séquences que nous récupérons restent du même type qu'elles étaient.

from collections import Sequence

def recursive_map (seq, func):
    for item in seq:
        if isinstance(item, Sequence):
            yield type(item)(recursive_map(item, func))
        else:
            yield func(item)

Démo :

>>> numbers = (1, 2, (3, (4, 5)), 7)
>>> mapped = recursive_map(numbers, str)
>>> tuple(mapped)
('1', '2', ('3', ('4', '5')), '7')

Ou un exemple plus complexe :

>>> complex_list = (1, 2, [3, (complex('4+2j'), 5)], map(str, (range(7, 10))))
>>> tuple(recursive_map(complex_list, lambda x: x.__class__.__name__))
('int', 'int', ['int', ('complex', 'int')], 'map')

def recursive_map(f, it):
    return (recursive_map(f, x) if isinstance(x, tuple) else f(x) for x in it)

Si vous souhaitez étendre votre résultat à dict , set et d'autres, vous pouvez utiliser la réponse d'Uriel :

from collections import Collection, Mapping

def recursive_map(data, func):
    apply = lambda x: recursive_map(x, func)
    if isinstance(data, Mapping):
        return type(data)({k: apply(v) for k, v in data.items()})
    elif isinstance(data, Collection):
        return type(data)(apply(v) for v in data)
    else:
        return func(data)

Teste l'entrée :

recursive_map({0: [1, {2, 2, 3}]}, str)

Rendement :

{0: ['1', '{2, 3}']}