2012-04-02 1 views
6

у меня есть простой класс с атрибутом, который может содержать список объектов одного и того же классаPython Рекурсия через объекты и дочерние объекты, номера глубины печати ребенка

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 

Работа с нашим «например» объект коробки, Я хотел бы, чтобы маневрировать через глубину всех возможных детей коробки он может иметь и распечатать объекты, отформатированные как так:

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

между использованием закладками не требуется, просто желая показать формат дерева ясно. Я могу спуститься по объектам и распечатать их названия, но я не могу распечатать передние номера, отображающие отношения родитель/ребенок. (1, 1,1, 1,2 ...)

Заранее спасибо за помощь :)

Edit Вот что я работаю с до сих пор

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 

ответ

7

Я думаю, это может быть полезно для вас, если я опубликую рабочий пример того, как это сделать, а не проходить через то, где у вас проблемы с кодом. Мы могли бы досконально понять это. У вашего кода есть правильная идея, что он должен отслеживать глубину по мере ее поступления. Но единственное, чего не хватает, это чувство вложенной глубины (дерева). Он знает только предыдущий node_count, а затем его текущий подсчет.

В моем примере используется замыкание для запуска объекта отслеживания глубины, а затем создается внутренняя функция для выполнения рекурсивной части.

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 

Пример вывод из ваших примеров:

>>> 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 

Ломая это вниз:

Мы первый принять аргумент окна, и автоматически преобразовать его локально в список, если бы вы только передается в одном поле. Таким образом, вы можете передать либо один объект коробки, либо список/кортеж из них.

depth - наш трекер глубины. Его список ints, который мы будем наращивать и сокращаться по мере рекурсии. Он начинается с 1 для первого элемента/первого уровня. Со временем это может выглядеть так: [1,1,2,3,1] в зависимости от того, насколько глубоко он проходит. Это основное различие между моим кодом и вашим. Каждая рекурсия имеет доступ к этому состоянию.

Теперь у нас есть эта внутренняя функция wrapped. Он собирается взять текущий элемент и распечатать его, а затем перебрать его детей.Мы получаем нашу строку печати, введя текущий список глубины, а затем имя.

Каждый раз, когда мы опускаемся в дочерний список, мы добавляем начальный уровень 1 в наш список глубины, и когда мы выходим из этого дочернего цикла, мы снова возвращаем его обратно. Для каждого дочернего элемента в этом цикле мы увеличиваем этот последний элемент вверх.

Внешняя часть этой функции wrapped внутренняя функция, тогда мы начинаем все, перебирая наши начальные поля, вызывая wrapped, а затем увеличивая наш первый уровень.

Внутренняя оберточная функция использует список глубин в закрытии. Я готов поспорить, что другие могут предложить некоторые дополнительные улучшения в этом, но это то, что я придумал для примера.

Примечание о аргументах для функции

Мы могли бы также спроектировал recurse вместо этого взять список переменной длины аргумента, вместо проверки списка. Это будет выглядеть следующим образом (и избавится от этой первой boxes = проверки):

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

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

И если вы изначально начать со списком элементов коробки, вы можете передать его выполнив:

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

Мне нравится ваш первый трюк с преобразованием окна локально в список. Также функция Wrapped читает намного лучше, чем две отдельные функции. Будет отредактировать мой код соответственно и отчитаться –

+0

Хорошо Разъяснено и отлично работает. Ваш код хорошо воспитал меня, я бы предпочел получить образование, чем набросился на меня код. Спасибо –

+0

@HackingLife: Обычно я просто прокомментирую ваш пример кода. Сначала каждый хочет увидеть, что вы пробовали, и где вы застряли. Увидев, что вы написали, я просто решил, что у вас уже есть правильная концепция. Рад, что это работает для вас! – jdi

1

У вас есть два варианты:

  1. Отслеживать дополнительную информацию в качестве дополнительного параметра в вашей рекурсии, например myRecursiveFunction(..., ancestry=[])
  2. Имейте каждый BoxItem отслеживать его родительский элемент, когда он встроен в BoxItem (в конструкторе __init__ для каждого ребенка задается child.parent = self). Это плохо, если вы планируете использовать BoxItem более чем в одной коробке.
+0

Почему что необходимо на основе фактического вопроса OPs? Он просто хочет, чтобы рекурсивная функция выполняла цикл каждого списка атрибутов boxItems в Boxitem. В его нынешнем классе нет ничего более необходимого для этого. Просто рекурсивная функция. – jdi

+0

@jdi: Это правильно, см. Параметр №1. Однако эта рекурсивная функция должна иметь память о принятых вызовах; снова см. вариант № 1 (альтернатива - вариант № 2). – ninjagecko

+0

А, я прочитал его более тщательно. Я убираю свой комментарий :-) Ваши первые предложения правильны. Вам нужно как-то отслеживать вашу глубину. – jdi

Смежные вопросы