2013-02-08 8 views
5

Sto ricorsivamente attraverso un file xml, usando etree.Python: evita il loop annidato sull'array

import xml.etree.ElementTree as etree 
tree = etree.parse('x.xml') 
root = tree.getroot() 
for child in root[0]: 
for child in child.getchildren(): 
     for child in child.getchildren(): 
      for child in child.getchildren(): 
       print(child.attrib) 

qual è il modo idiomatico in python per evitare questi loop annidati.

getchildren() ⇒ list of Element instances [#] 
    Returns all subelements. The elements are returned in document order. 

Returns: 
A list of subelements. 

Ho visto alcuni post nel SO come, Avoiding nested for loops ma non fa direttamente traducono in mio uso.

grazie.

+1

'itertools.product' è un buon modo per evitare cicli annidati. Perché non si traduce nel tuo utilizzo? –

+0

Vuoi specificamente gli attributi per gli elementi di 4 bambini profondi? – bogatron

+0

scusa, non intendevo itertools.product non mi va bene, ma non potevo tradurre quell'esempio in matrici come nel mio caso. Non ho fatto molto Python, ma ci proverò. – bsr

risposta

3

Se si desidera ottenere i bambini che sono n livelli di profondità nella struttura, e quindi scorrere di loro, si può fare:

def childrenAtLevel(tree, n): 
    if n == 1: 
     for child in tree.getchildren(): 
      yield child 
    else: 
     for child in tree.getchildren(): 
      for e in childrenAtLevel(child, n-1): 
       yield e 

Poi, per ottenere gli elementi di quattro livelli di profondità, si farebbe semplicemente dire:

for e in childrenAtLevel(root, 4): 
    # do something with e 

Oppure, se si vuole ottenere tutti i nodi foglia (cioè i nodi che non hanno figli stessi), si può fare:

def getLeafNodes(tree): 
    if len(tree) == 0: 
     yield tree 
    else: 
     for child in tree.getchildren(): 
      for leaf in getLeafNodes(child): 
       yield leaf 
2

itertools.chain.from_iterable appiattirà un livello di annidamento; è possibile utilizzare functools.reduce di applicarla n volte (Compressing "n"-time object member call):

from itertools import chain 
from functools import reduce 

for child in reduce(lambda x, _: chain.from_iterable(x), range(3), root): 
    print(child.attrib) 

noti che getchildren è deprecato; l'iterazione di un nodo produce direttamente i suoi figli.