2009-09-11 6 views
1

Quelle est la manière pythonique d'effectuer cette boucle. J'essaie de choisir une clé aléatoire qui retournera un sous-arbre et non la racine. Par conséquent: 'parent == Aucun' ne peut pas être vrai. 'IsRoot == True' ne peut pas non plus être vrai.Python: quelle est la manière pythonique de réaliser cette boucle?

thekey = random.choice(tree.thedict.keys()) 
while (tree.thedict[thekey].parent == None)or(tree.thedict[thekey].isRoot == True): 
     thekey = random.choice(tree.thedict.keys()) 
....... 

edit: il fonctionne maintenant

+3

Qu'essayez-vous exactement de faire? – freiksenet

+0

Connaître le type des valeurs dans 'thedict' serait très utile. – Triptych

+0

obtenir une sous-arborescence aléatoire qui n'est pas la racine. donc si le parent est none, ou que le flag 'isRoot' est vrai, je veux qu'il obtienne une autre clé aléatoire, puis vérifie-le –

Répondre

3
key = random.choice([key for key, subtree in tree.thedict.items() 
         if subtree.parent and not subtree.isRoot]) 

(corrigé après les commentaires et édition question)

+0

Cela ne fait pas exactement la même chose. Cela peut être omettre le code du corps de la boucle d'une plus grande boucle qui fait des choses à thedict. –

+0

Il n'y a pas de plus grande boucle. Cela semble très succinct. –

+0

C'est une façon très coûteuse de résoudre le problème. Vous construisez une liste de toutes les clés et sous-arbres dans l'arbre, ce qui sera lent et prendra beaucoup de mémoire si l'arbre est grand. Ensuite, cette liste est utilisée une seule fois et rejetée. Si vous savez que l'arbre sera toujours petit, alors ce code succinct pourrait être un bon choix. Mais si vous étiez en train de mettre ça dans une bibliothèque, je ne ferais pas ça de cette façon. D'autres solutions, qui utilisent une boucle pour réessayer si le choix aléatoire est la racine, exécuteront presque toujours la boucle exactement une fois, et n'auront pas besoin de stockage supplémentaire. – steveha

1
thekey = random.choice(tree.thedict.keys()) 
parent = thedict[thekey].parent 
while parent is None or parent.isRoot: 
    thekey = random.choice(tree.thedict.keys()) 
    parent = thedict[thekey].parent 
+1

Vous avez annulé le premier test conditionnel. – Triptych

+2

beaucoup plus lisible. –

+1

Aussi, 'thekey.parent' n'a aucun sens. – Triptych

3

obtenir un sous-arbre aléatoire qui n'est pas la racine

not_root_nodes = [key, node for key,node in tree.thedict.iteritems() if not (node.parent is None or node.isRoot)] 
item = random.choice(not_root_nodes) 
+1

Cela ne fonctionnera pas, car 'random.choice' ne prend pas les générateurs comme arguments. L'argument devrait être une liste. –

+0

Cela construit une liste de tous les nœuds dans l'arborescence, chaque fois que vous l'exécutez; puis il choisit un nœud et rejette la liste. Pour les grands arbres, ce sera très cher. J'espère que nous pourrons trouver une solution plus efficace. – steveha

1

Je pense que c'est un peu mieux:

theDict = tree.thedict 

def getKey(): 
    return random.choice(theDict.keys()) 

theKey = getKey() 

while theDict[thekey].parent in (None, True): 
    thekey = getKey() 

Que pensez-vous?

+0

Qu'est-ce que cela signifie pour theDict [thekey] .parent d'être True? Vous devez vérifier si theDict [thekey] .isRoot est True. – ntownsend

+0

Je pense qu'il cherchait isRoot == True, pas parent == True. :-) – Ken

+0

Je voulais le faire sans utiliser de fonction –

0
def is_root(v): 
    assert (v.parent != None) == (v.isRoot) 
    return v.isRoot 
    #note how dumb this function looks when you guarantee that assertion 

def get_random_nonroot_key(): 
    while True: 
    thekey = random.choice(tree.thedict.keys()) 
    value = tree.thedict[thekey] 
    if not is_root(value): return key 

ou un refactoring de la réponse de Roberto Bonvallet

def get_random_nonroot_key(): 
    eligible_keys = [k for k, v in tree.thedict.items() if not is_root(v)] 
    return random.choice(eligible_keys) 
0

Je pense que votre tout état est défectueux:

Je pense que vous attendez ceci: tree.thedict[thekey].parent == None
doit être égale à celle-ci: tree.thedict[thekey].parent.isRoot == True

Quand en fait, pour les deux à dire « ce noeud n'est pas la racine », vous devez changer la deuxième déclaration: tree.thedict[thekey].isRoot == True

Comme écrit, votre test conditionnel dit « alors que ce nœud est la racine ou cette le parent du nœud est la racine ". Si votre structure arborescente est un seul nœud racine avec de nombreux nœuds feuilles, vous devriez vous attendre à une boucle infinie dans ce cas.

est ici une ré-écriture:

thekey = random.choice(k for k in tree.thedict.keys() if not k.isRoot) 
+0

Oui, vous avez raison. Après avoir changé mon code, il fonctionne maintenant –

0
thekey = random.choice(tree.thedict.keys()) 
parent = tree.thedict[thekey].parent 
while parent is None or tree.thedict[thekey].isRoot: 
    thekey = random.choice(tree.thedict.keys()) 
    parent = thedict[thekey].parent 
+0

Cela semble un peu plus lisible. Je vois que vous avez attrapé mon erreur en référant '.parent' dans la deuxième condition. –

0

Personnellement, je n'aime pas la répétition d'initialisation thekey avant que la boucle while, puis à nouveau dans la boucle. C'est une source possible de bugs; que se passe-t-il si quelqu'un édite l'une des deux initialisations et oublie d'éditer l'autre? Même si cela ne se produit jamais, quiconque lit le code doit vérifier soigneusement que les deux initialisations correspondent parfaitement.

je l'écrire comme ceci:

while True: 
    thekey = random.choice(tree.thedict.keys()) 
    subtree = tree.thedict[thekey] 
    if subtree.parent is not None and not subtree.isRoot: 
     break 

post-scriptum Si vous voulez vraiment juste le sous-arbre, et ne se soucient pas de la clé nécessaire pour rechercher la sous-arborescence, vous pouvez même le faire:

while True: 
    subtree = random.choice(tree.thedict.values()) 
    if subtree.parent is not None and not subtree.isRoot: 
     break 

Certaines personnes peuvent ne pas aimer l'utilisation de « while True: », mais qui est le idiome Python standard pour "boucle pour toujours jusqu'à ce que quelque chose fonctionne break".À mon humble avis, c'est simple, clair, Python idiomatique.

P.P.S. Ce code devrait vraiment être enveloppé dans une instruction if qui vérifie que l'arbre a plus d'un nœud. Si l'arbre a seulement un nœud racine, ce code serait bouclé pour toujours.

+0

Je ne connaissais pas 'true while: break' et je ne l'aurais pas vu comme pythonic. Je serai une chose pratique à savoir. –

Questions connexes