2012-04-02 9 views
6

ich eine einfache Klasse mit einem Attribut haben, die eine Liste von Objekten der gleichen KlassePython Rekursion durch Objekte und untergeordneten Objekten, Drucken Kind Tiefe Zahlen

class BoxItem: 
    def __init__(self, name, **kw): 
     self.name = name 
     self.boxItems = [] 
     ... #more attributes here 

box1 = BoxItem('Normal Box') 
box2 = BoxItem('Friendly Box') 
box3 = BoxItem('Cool Box') 
box4 = BoxItem('Big Box', [box1, box2]) #contains some children 
example = BoxItem('Example Box', [box4,box3]) #contains another level of children 

Arbeiten mit unserem ‚Beispiel‘ Box-Objekt enthalten kann, ich mag durch die Tiefen alle mögliche Box Kinder manövrieren kann es haben, und die Objekte wie so formatierten ausdrucken:

1 Example Box 
1.1 Big Box 
    1.1.1 Normal Box 
    1.1.2 Friendly Box 
1.2 Cool Box 

Das Tabbing zwischen nicht benötigt wird, nur will das Baumformat deutlich zeigen. Ich bin in der Lage, die Objekte selbst zu durchlaufen und ihre Titel auszudrucken, aber ich kann die vorderen Zahlen, die die Eltern/Kind-Beziehung zeigen, nicht ausdrucken. (1, 1.1, 1.2 ...)

Vielen Dank im Voraus für Ihre Hilfe :)

bearbeiten Hier ist, was ich mit so weit

def print_boxes(box_list): 
    node_count = 0 
    for box in box_list: 
    node_count += 1 
    print str(node_count)+' '+box.name #prints out the root box 
    recursive_search(box,node_count) 

def recursive_search(box,node_count): #recursive automatically 
    level = 0 
    for child in box.boxItems: 
    level += 1 
    for x in range(len(child.boxItems)): 
     print x+1 #this prints out some proper numbers 
    print "level: "+str(level) #experiment with level 
    print child.name #prints out child box name 
    recursive_search(child,node_count) #runs the function again inside the function 

Antwort

7

Ich denke, es könnte hilfreicher für Sie sein, wenn ich ein funktionierendes Beispiel dafür schreibe, im Gegensatz dazu, wo Code ausgeführt wird. Wir könnten auf diese Weise schneller zu einem Verständnis kommen. Ihr Code hat die korrekte Idee, dass er die Tiefe verfolgen muss. Aber das einzige, was es fehlt, ist ein Gefühl der verschachtelten Tiefe (Baum). Es kennt nur die vorherige node_count und dann die aktuelle Kinderzahl.

Mein Beispiel verwendet eine Schließung, um das Tiefenverfolgungsobjekt zu starten, und erstellt dann eine innere Funktion, um den rekursiven Teil auszuführen.

def recurse(box): 

    boxes = not isinstance(box, (list, tuple)) and [box] or box 

    depth = [1] 

    def wrapped(box): 

     depthStr = '.'.join([str(i) for i in depth]) 
     print "%s %s" % (depthStr, box.name) 

     depth.append(1) 
     for child in box.boxItems: 
      wrapped(child) 
      depth[-1] += 1 
     depth.pop() 

    for box in boxes: 
     wrapped(box) 
     depth[0] += 1 

Beispiel für die Ausgabe von Ihrem Beispiele:

>>> recurse(example) 
1 Example Box 
1.1 Big Box 
1.1.1 Normal Box 
1.1.2 Friendly Box 
1.2 Cool Box 

>>> recurse([example, example]) 
1 Example Box 
1.1 Big Box 
1.1.1 Normal Box 
1.1.2 Friendly Box 
1.2 Cool Box 
2 Example Box 
2.1 Big Box 
2.1.1 Normal Box 
2.1.2 Friendly Box 
2.2 Cool Box 

brechen diese nach unten:

Wir zunächst eine Box Argument akzeptieren, und es automatisch lokal in eine Liste konvertieren, wenn Sie hatte in einem einzigen Box-Artikel übergeben. Auf diese Weise können Sie entweder ein Box-Objekt oder eine Liste/ein Tupel von ihnen übergeben.

depth ist unser Tiefen-Tracker. Es ist eine Liste von Ints, die wir aufbauen und verkleinern werden, wenn die Rekursion stattfindet. Es beginnt bei 1 für das erste Element/erste Ebene. Im Laufe der Zeit kann es wie folgt aussehen: [1,1,2,3,1] je nachdem wie tief es durchquert. Dies ist der Hauptunterschied zwischen meinem Code und Ihrem. Jede Rekursion hat Zugriff auf diesen Status.

Jetzt haben wir diese innere wrapped Funktion. Es wird ein aktuelles Boxelement genommen und gedruckt und dann über seine Kinder iteriert.Wir erhalten unsere Druckzeichenfolge, indem wir der aktuellen Tiefenliste und dann dem Namen beitreten.

Jedes Mal, wenn wir in eine Child-Liste verzweigen, fügen wir eine Start-Level 1 zu unserer Tiefenliste hinzu, und wenn wir diese Child-Schleife verlassen, setzen wir sie wieder ab. Für jedes Kind in dieser Schleife erhöhen wir das letzte Element.

Außerhalb dieser wrapped inneren Funktion, starten wir dann das Ganze durch Schleifen über unsere ersten Boxen, wrapped aufrufen und dann inkrementieren unsere erste Ebene.

Die innere umbrochene Funktion verwendet die Tiefenliste in einem Abschluss. Ich wage zu wetten, dass andere hier noch weitere Verbesserungen anbieten können, aber dafür habe ich mir ein Beispiel ausgedacht.

Hinweis über die args für die Funktion

Wir auch recurse entworfen haben könnten stattdessen eine Liste mit variabler Länge Argumente zu nehmen, anstatt eine Liste von zu überprüfen. Es würde wie folgt aussehen (und würde dieses ersten boxes = Scheck loszuwerden):

def recurse(*boxes): 
    #boxes will always come in as a tuple no matter what 

>>> recurse(example) 
>>> recurse(example, example, example) 

Und wenn Sie ursprünglich mit einer Liste von Feldelemente starten, können Sie es passieren, indem Sie:

>>> boxes = [example, example, example] 
>>> recurse(*example) # this will unpack your list into args 
+0

Ich mag Ihren ersten Trick mit der Umwandlung der Box lokal zu einer Liste. Auch die Wrapped-Funktion liest viel besser als zwei getrennte Funktionen. Will meinen Code entsprechend bearbeiten und melde mich wieder –

+0

Gut erklärt und funktionierte perfekt. Dein Code hat mich gut erzogen, ich wäre lieber erzogen als eine Codierungsantwort auf mich geworfen zu haben. Vielen Dank –

+0

@HackingLife: Normalerweise würde ich nur Ihr Code Beispiel kommentieren. Am Anfang möchte jeder sehen, was du versucht hast und wo du feststeckst. Nachdem ich gesehen habe, was du geschrieben hast, habe ich einfach entschieden, dass du schon das richtige Konzept hast. Schön, dass es für dich funktioniert! – jdi

1

arbeiten Sie haben zwei Optionen:

  1. Behalten Sie die zusätzlichen Informationen als zusätzlichen Parameter in Ihrer Rekursion, z myRecursiveFunction(..., ancestry=[])
  2. Lassen Sie jedes BoxItem das übergeordnete Objekt verfolgen, wenn es in ein BoxItem eingebettet ist (setzen Sie im __init__-Konstruktor child.parent = self für jedes untergeordnete Element). Dies ist schlecht, wenn Sie ein BoxItem in mehr als einer Box haben möchten.
+0

Warum Ist dies auf der Grundlage der tatsächlichen Frage des OP erforderlich? Er möchte nur eine rekursive Funktion, um die BoxItems-Attributliste jedes Boxitems zu durchlaufen. In seiner jetzigen Klasse ist dazu nichts mehr nötig. Nur eine rekursive Funktion. – jdi

+0

@jdi: Das ist richtig, siehe Option # 1. Diese rekursive Funktion muß jedoch eine Erinnerung an die ausgeführten Anrufe haben; siehe Option # 1 (die Alternative ist Option # 2). – ninjagecko

+0

Ah, ich lese es genauer. Ich ziehe meinen Kommentar zurück :-) Ihr erster Vorschlag ist korrekt. Sie müssen einige, wie Sie Ihre Tiefe verfolgen – jdi