2015-04-09 1 views
6

Je souhaite mapper une valeur plusieurs fois dans un dictionnaire et enregistrer les valeurs intermédiaires. Puisque list.append() ne renvoie pas de valeur, voici le meilleur que j'ai pu trouver. Y at-il une meilleure façon de le faire en Python, peut-être en utilisant une compréhension de liste ou une récursivité?Multi-mappage d'une valeur lors de l'enregistrement des valeurs intermédiaires

def append(v, seq): 
    seq.append(v) 
    return v 

def multimap(value, f, count): 
    result = [] 
    for _ in range(count): 
     value = append(f[value], result) 

    return result 

print(multimap('a', {'a': 'b', 'b': 'c', 'c': 'd', 'd': 'a'}, 4)) 

Sortie:

['b', 'c', 'd', 'a'] 
+2

Êtes-vous le 2 ou 3? Il semble que itertools.accumulate puisse le faire. – user2357112

+0

@ user2357112: La question se posait dans le contexte de Py 3, mais il serait assez facile d'écrire une version simplifiée de 'accumulate' pour la version Py 2 (comme je l'ai fait occasionnellement) - bien que la première réponse de @ shx2 ci-dessous, qui est très similaire à cela, fonctionnerait dans les deux versions. – martineau

Répondre

5

au lieu d'avoir à traiter avec des listes, vous pouvez simplement utiliser un générateur:

def multimap(value, f, count): 
    for _ in range(count): 
     value = f[value] 
     yield value 

print(list(multimap('a', {'a': 'b', 'b': 'c', 'c': 'd', 'd': 'a'}, 4))) 
+1

J'aime cette approche ... et en faire un générateur pourrait être utile dans d'autres contextes plus itératifs, – martineau

0

Vous pouvez aussi le faire:

def multimap(val, f, count): 
    result = [] 
    _ = [result.append(f[result[-1]] if result else f[val]) for _ in range(count)] 
    return result 


>>> multimap('a', {'a': 'b', 'b': 'c', 'c': 'd', 'd': 'a'}, 4) 
['b', 'c', 'd', 'a'] 

Mais je ne pense pas que cela compte comme un python-esque lution.

+0

Bien qu'il y ait une compréhension de liste impliquée, c'est gaspilleur car il est exécuté uniquement pour ses effets secondaires. – martineau

1

Une autre solution, inspirée de la programmation fonctionnelle. Cette solution est récursive et totalement inefficace.

def multimap(value, f, count): 
    if count <= 0: 
     return [] 
    return [ f[value] ] + multimap(f[value], f, count - 1) 
+1

+1 pour l'élégance et le potentiel one-liner-ness: 'return [f [valeur]] + multimap (f [valeur], f, compte-1) si compte> 0 else []'. Dommage pour l'inefficacité ... – martineau

1

Peu de temps après que je posté ma question et à gauche pendant un certain temps pour saisir un octet à manger, je pensais à une réponse qui est différent de tous les autres affiché jusqu'ici ... et après une petite optimisation est, mis à part une certaine initialisation, relativement simple.

L'un des arguments à la fonction est count, ce qui permet d'initialiser partiellement la liste obtenue à l'avance, ce qui élimine la nécessité de le construire progressivement avec plusieurs append appels:

def multimap(value, f, count): 
    result = [] if count < 1 else [f[value]] + [None]*(count-1) 
    for i in range(1, count): 
     result[i] = f[result[i-1]] 
    return result