Pretty Print output in a sideways tree format in console window
Asked Answered
F

3

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.

Fuchs answered 4/9, 2012 at 1:40 Comment(0)
S
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
Subliminal answered 23/6, 2013 at 11:23 Comment(0)
P
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
Pontonier answered 4/9, 2012 at 9:39 Comment(4)
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 exampleFuchs
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.Pontonier
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?Fuchs
@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.Pontonier
F
-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
Fanaticize answered 4/9, 2012 at 1:56 Comment(4)
Looks good...any way to make it similar to the pretty print tree one where it has a tree format?Fuchs
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.Fanaticize
Using the name of a keyword like dict for an argument or variable name is considered bad form, as is type-checking.Pontonier
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.Fanaticize

© 2022 - 2024 — McMap. All rights reserved.