views:

80

answers:

2

I have table that looks like this:

id  | parentid | name
---------------------
 1  |    0     | parent1
---------------------
 2  |    0     | parent2
---------------------
 3  |    1     | child1
---------------------
 4  |    3     | subchild1

I'm now trying to come up with an efficient way to take that database data and create a Python dictionary.

Basically, I want to be able to do:

tree = expand(Session.query(mytable).all())
print tree['parent2']['child2']

# result would be 'subchild1'

I'm at a complete loss with how to do this... I've been messing around with the following function but I can't get it working. Any help would be appreciated.

def expand(tree):

   parents = [i for i in tree if i.parentid == 0]

   for parent in parents:
      children = expand(parent)
+1  A: 

If I understand correctly, the item for which their parent id is 0 are the root one or the first level ?

If so, your method should look like:

def expand(tree, id):
    expanded_tree = {}

    parents = [i for i in tree if i.parentid == id]

    for parent in parents:
        expanded_tree[parent.name] = expand(tree, parent.id)

    return expanded_tree

and you'd start it like:

tree = expand(Session.query(mytable).all(), 0)
Eric Fortin
I just fixed his code for recursion. Either it's missing the end of the function or he has an error in it but yes like it is, it would since there is no return statement.
Eric Fortin
How would you then return the tree? Returning data in recursive functions goes completely over my head
Steve
Completed function to show you how it could be done by recursion although THC4k is right, recursion is not the best solution for this problem.
Eric Fortin
+1  A: 

Your example doesn't match the data given but this should be what you want.

It's not recursive, because recursion does not make sense here: The input data has no recursive structure (that's what we are creating), so all you can write as a recursion is the loop ... and that is a pretty pointless thing to do in Python.

data = [ (1,0,"parent1"), (2,0,"parent2"), (3,1,"child1"), (4,3,"child2")]

# first, you have to sort this by the parentid
# this way the parents are added before their children
data.sort(key=lambda x: x[1])

def make_tree( data ):
    treemap = {} # for each id, give the branch to append to
    trees = {}
    for id,parent,name in data:
        # {} is always a new branch
        if parent == 0: # roots
            # root elements are added directly
            trees[name] = treemap[id] = {}
        else:
            # we add to parents by looking them up in `treemap`
            treemap[parent][name] = treemap[id] = {}

    return trees

tree = make_tree( data )
print tree['parent1']['child1'].keys() ## prints all children: ["child2"]
THC4k
+1 Can we skip the sorting step by initializing the tree map as the first step in `make_tree`? For example: `treemap = dict( (d[0], {}) for d in data )`.
FM
@FM: Yeah that works too. But I'd rather ask the DB for a sorted list :]
THC4k