-2

What is the fastest way to create a family tree out of a dict that looks like this:

family = [
    {'name': 'a', 'parent': ''},
    {'name': 'b', 'parent': 'a'},
    {'name': 'c', 'parent': 'a'},
    {'name': 'd', 'parent': 'b'},
    {'name': 'e', 'parent': 'd'},
    {'name': 'f', 'parent': ''},
    {'name': 'g', 'parent': 'f'},
    {'name': 'h', 'parent': 'a'}
]

Ultimately, I am trying to print it out (with a ton of extra info, but this is the general idea), a list like this:

a
  b
    d
      e
  c
  h
f
  g

Is the solution to create a function to loop over the list until it is empty, using .pop() on each item it finds the parent to? Or is there a better way in python?

This is a part of a much bigger problem, however, I am trying to find the best way to do this small little part. So even tho a nightmare of lambda's is probably possible. Please try to answer in a clean way which is easily extendable :)

xeor
  • 5,301
  • 5
  • 36
  • 59
  • 2
    -1. Okay, so you have not tried anything but want us to write the code for you. This site is for learning, not outsourcing work to volunteers. – Ferdinand Beyer Nov 11 '13 at 09:10
  • I have tried to do this using a while loop, and pop() on each item while I try to find its place. Then put that item inside a bigger dict to keep track of the tree. However, it doesn't feel like that is the best solution since I have to go over the list many times. I don't have any code for this since I didn't finish it, mainly because I wanted to ask if there was a better, maybe even built-in way of doing this. – xeor Nov 11 '13 at 09:21
  • There is no limit of how many children a parent can have, nor how deep this tree can be. – xeor Nov 11 '13 at 09:22

2 Answers2

3

I suggest processing your list of dicts into a more useful data structure. I'd make a dictionary mapping from a parent to a list of their children (the "ancestors", who have no parents will be included as the "children" of the empty string).

Then, recursively apply the following algorithm to print out the tree, starting with the list of ancestors and depth 0:

  1. Iterate over the people in the input list (if the list is empty, this do nothing, as our base case).
  2. For each person, first print their name preceded by depth spaces.
  3. Look up the list of that person's children from our dictionary, and recurse, with a depth one greater.
  4. Continue onto the next person.

Here's the code:

from collections import defaultdict

def preprocess(family_list):
    descent_dict = defaultdict(list)
    for person in family_list:
        descent_dict[person["parent"]].append(person["name"])
    return descent_dict

def print_family_tree(descent_dict, people, depth=0):
    for person in people:
        print("  "*depth+person)
        print_family_tree(descent_dict, descent_dict[person], depth+1)

Example run:

>>> family = [
    {'name': 'a', 'parent': ''},
    {'name': 'b', 'parent': 'a'},
    {'name': 'c', 'parent': 'a'},
    {'name': 'd', 'parent': 'b'},
    {'name': 'e', 'parent': 'd'},
    {'name': 'f', 'parent': ''},
    {'name': 'g', 'parent': 'f'},
    {'name': 'h', 'parent': 'a'}
]

>>> d = preprocess(family)
>>> print_family_tree(d, d[''])
a
  b
    d
      e
  c
  h
f
  g
Blckknght
  • 100,903
  • 11
  • 120
  • 169
1

WARNING - THIS IS A BAD SOLUTION

Use the answer below from @Blckknght instead. This is a poor solution that runs at O(N**2) as it relies on a badly formatted data structure.

You'll want to use a recursive function that takes in a root node, prints all children of that node and then calls itself. Something like the below. Don't try to edit the family dict in place, you'll just make your life harder than it needs to be.

Something like that the function below might work for you. Bare in mind that this is just a quick example and you'll need to add a fair bit of error handling and that to avoid it blowing up if you have a cycle or owt.

INDENT = ' ' #Change this to taste

def print_family(parent,family,indent=0):
    for child in family:
        if child['parent'] == parent:

             # Print here
             print '%s%s' % (INDENT * indent,child['name'])

             # Call on the child
             print_family(child['name'],family,indent + 1)

# Kick it off with the root node
print_family('',family)
wdh
  • 1,612
  • 12
  • 16
  • This is just what I where looking for, thanks!! I think I overcomplicated the problem I had, this is simple and perfect. – xeor Nov 11 '13 at 09:38
  • 2
    This code is needlessly wasteful, mostly because it relies on the fairly useless list of dicts provided as input, rather than building a more capable data structure. It takes `O(N**2)` time to print out the results, when it is easy enough to do it in `O(N)` time. – Blckknght Nov 11 '13 at 09:48
  • Good point @Blckknght. I should have noticed that (what I get for quickly typing up SO answers when I should be working) I've edited my answer. – wdh Nov 11 '13 at 11:15