5

I have a dictionary such as this created using Python.

d = {'a': ['Adam', 'Book', 4], 'b': ['Bill', 'TV', 6, 'Jill', 'Sports', 1, 'Bill', 'Computer', 5], 'c': ['Bill', 'Sports', 3], 'd': ['Quin', 'Computer', 3, 'Adam', 'Computer', 3], 'e': ['Quin', 'TV', 2, 'Quin', 'Book', 5], 'f': ['Adam', 'Computer', 7]}

I wanted to print this out in a sideways tree format rather on the console. I've tried pretty print but when the dictionary gets long, it becomes difficult to read.

For example, with this dictionary, it would return:

a -> Book -> Adam -> 4
b -> TV -> Bill -> 6
  -> Sports -> Jill -> 1
  -> Computer -> Bill -> 5
c -> Sports -> Bill -> 3
d -> Computer -> Quin -> 3
              -> Adam -> 3
e -> TV -> Quin -> 2
    Book -> Quin -> 5
f -> Computer -> Adam -> 7

Essentially, the pretty print is organized by the Activity, or the item in second position in the list, then by name and then by the number.

The sample output above is just an example. I tried working with Pretty print a tree but was unable to figure out how to turn that into a sideways format.

Community
  • 1
  • 1
user1530318
  • 25,507
  • 15
  • 37
  • 48

3 Answers3

8

You can have a look at the code of the ETE toolkit. The function _asciiArt produces nice representations of trees even with internal node labels

from ete2 import Tree
t = Tree("(((A,B), C), D);")
print t

#               /-A
#          /---|
#     /---|     \-B
#    |    |
#----|     \-C
#    |
#     \-D
Community
  • 1
  • 1
rme
  • 81
  • 1
  • 1
3

Here's how I would do it. Since the tree is only two levels deep -- despite what your desired output format might seem to imply -- there's no need to use recursion to traverse its contents, as iteration works quite well. Probably this is nothing like the #f code you referenced, since I don't know the language, but it's a lot shorter and more readable -- at least to me.

from itertools import izip

def print_tree(tree):
    for key in sorted(tree.iterkeys()):
        data = tree[key]
        previous = data[0], data[1], data[2]
        first = True
        for name, activity, value in izip(*[iter(data)]*3):  # groups of three
            activity = activity if first or activity != previous[1] else ' '*len(activity)
            print '{} ->'.format(key) if first else '    ',
            print '{} -> {} -> {}'.format(activity, name, value)
            previous = name, activity, value
            first = False

d = {'a': ['Adam', 'Book', 4],
     'b': ['Bill', 'TV', 6, 'Jill', 'Sports', 1, 'Bill', 'Computer', 5],
     'c': ['Bill', 'Sports', 3],
     'd': ['Quin', 'Computer', 3, 'Adam', 'Computer', 3],
     'e': ['Quin', 'TV', 2, 'Quin', 'Book', 5],
     'f': ['Adam', 'Computer', 7]}

print_tree(d)

Output:

a -> Book -> Adam -> 4
b -> TV -> Bill -> 6
     Sports -> Jill -> 1
     Computer -> Bill -> 5
c -> Sports -> Bill -> 3
d -> Computer -> Quin -> 3
              -> Adam -> 3
e -> TV -> Quin -> 2
     Book -> Quin -> 5
f -> Computer -> Adam -> 7

Update

To organize the output by name instead of activity you'd need to change three lines as indicated below:

from itertools import izip

def print_tree(tree):
    for key in sorted(tree.iterkeys()):
        data = tree[key]
        previous = data[0], data[1], data[2]
        first = True
        for name, activity, value in sorted(izip(*[iter(data)]*3)):  # changed
            name = name if first or name != previous[0] else ' '*len(name) # changed
            print '{} ->'.format(key) if first else '    ',
            print '{} -> {} -> {}'.format(name, activity, value) # changed
            previous = name, activity, value
            first = False

Output after modification:

a -> Adam -> Book -> 4
b -> Bill -> Computer -> 5
          -> TV -> 6
     Jill -> Sports -> 1
c -> Bill -> Sports -> 3
d -> Adam -> Computer -> 3
     Quin -> Computer -> 3
e -> Quin -> Book -> 5
          -> TV -> 2
f -> Adam -> Computer -> 7
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Also, how would I do it if I wanted it organized by the name and not by the activity, so organized by the first element in the list, not the second. a -> adam -> book -> 4 for example – user1530318 Sep 04 '12 at 18:09
  • Yes, line 3 was wrong (a leftover from before I made it a function). I've fixed that as well as updated my answer to show hot to modify it to organize the output by name rather than by activity. – martineau Sep 04 '12 at 19:10
  • Only one issue that I'm having, don't know if its just me or you see it too but everything is like two spaces off. For example, b -> Bill -> Computer -> 5 -> TV -> 6 Jill -> Sports -> 1 The jill and the -> above it would be two spaces to the left. Tried to play around with your code but couldn't figure it out. Any idea? – user1530318 Sep 04 '12 at 21:54
  • @user1530318: The outputs shown in my answer are exactly what each version of the program displayed given the input dictionary `d` shown -- which I just re-verified -- so it must be something on your end. Only thing I can think of is perhaps there are extra spaces in some of the data strings in the dictionary you're using. Also note the only thing changed in line 8 of the second version was the addition of a call to `sorted()` around the `izip()` call. – martineau Sep 05 '12 at 01:06
-1
def treePrint(tree):
    for key in tree:
        print key, # comma prevents a newline character
        treeElem = tree[key] # multiple lookups is expensive, even amortized O(1)!
        for subElem in treeElem:
            print " -> ", subElem,
            if type(subElem) != str: # OP wants indenting after digits
                print "\n " # newline and a space to match indenting
        print "" # forces a newline
rsegal
  • 401
  • 3
  • 11
  • Looks good...any way to make it similar to the pretty print tree one where it has a tree format? – user1530318 Sep 04 '12 at 02:12
  • If you're looking for some sort of recursive tree-depth solution, you could have a base case where the data isn't iterable, otherwise recurse. I don't know the pprint module very well so I don't really know what you're hoping I can do. – rsegal Sep 04 '12 at 02:27
  • Using the name of a keyword like `dict` for an argument or variable name is considered bad form, as is type-checking. – martineau Sep 04 '12 at 10:06
  • Good call on the `dict` thing. In retrospect I should have done the `zip` thing that martineau used instead of type-checking, but the "ending in a number" pattern was more obvious than the "group of three" pattern. – rsegal Sep 04 '12 at 13:15