2009-06-19 4 views
1

J'ai essayé de trouver un moyen de parcourir une structure hiérarchique, comme une liste chaînée, en utilisant une expression de liste, mais je n'ai rien trouvé qui semble fonctionner.Comment parcourir une liste liée en utilisant une compréhension de liste?

Fondamentalement, je veux convertir ce code:

p = self.parent 
names = [] 
while p: 
    names.append(p.name) 
    p = p.parent 
print ".".join(names) 

dans un one-liner comme:

print ".".join([o.name for o in <???>]) 

Je ne sais pas comment faire le traversal dans la partie ???, bien que , d'une manière générique (si c'est encore possible). J'ai plusieurs structures avec des attributs de type .parent similaires, et je ne veux pas écrire une fonction de rendement pour chacun.

Edit:

Je ne peux pas utiliser les méthodes de l'objet lui-même __iter__ parce que son déjà utilisé pour itérer sur les valeurs contenues dans l'objet lui-même. La plupart des autres réponses, sauf pour liori, hardcode le nom de l'attribut, ce que je veux éviter.

Voici mon adaptation basée sur la réponse de Liori:

import operator 
def walk(attr, start): 
    if callable(attr): 
    getter = attr 
    else: 
    getter = operator.attrgetter(attr) 

    o = getter(start) 
    while o: 
    yield o 
    o = getter(o) 

Répondre

2

Si vous voulez que votre solution soit générale, utiliser une techique générale. Ceci est un point fixe comme générateur:

def fixedpoint(f, start, stop): 
    while start != stop: 
     yield start 
     start = f(start) 

Il retournera un départ rendement du générateur, f (démarrage), f (f (début)), f (f (f (démarrage))), .. ., tant qu'aucune de ces valeurs n'est égale à l'arrêt.

Utilisation:

print ".".join(x.name for x in fixedpoint(lambda p:p.parent, self, None)) 

Ma bibliothèque personnelle aides a la même fonction comme FixedPoint pendant des années ... il est très utile pour les hacks rapides.

+0

oui! C'est le genre de chose que je cherchais. J'ai mis à jour ma réponse avec mon adaptation. –

+0

'fixedpoint' peut être écrit comme en termes de [cfor'] de David X (http://stackoverflow.com/questions/2740901/simulating-c-style-for-loops-in-python/2741943#2741943) un peu Fonction plus générale: 'def point fixe (f, start, stop): retourne cfor (début, lambda courant: courant! = stop, f)' –

1

Liste compréhension fonctionne avec des objets qui sont itérateurs (ont la méthode suivante()). Vous devez définir un itérateur pour votre structure afin de pouvoir l'itérer de cette façon.

6

La chose la plus proche que je peux penser est de créer un générateur de parent:

# Generate a node's parents, heading towards ancestors 
def gen_parents(node): 
    node = node.parent 
    while node: 
     yield node 
     node = node.parent 

# Now you can do this 
parents = [x.name for x in gen_parents(node)] 
print '.'.join(parents) 
1

Votre LinkedList doit être itérable pour que cela fonctionne correctement.

Here's a good resource on it. (PDF warning) Il est très détaillé sur les itérateurs et les générateurs.

Une fois que vous faites cela, vous serez en mesure de faire ceci:

print ".".join([o.name for o in self]) 
+0

Ce PDF est un accès restreint ... peut-être rendre l'information disponible? – SumNeuron

Questions connexes