7
\$\begingroup\$

Goal:

A tree can be represented as a nested list: the list elements represent nodes, and a node is a pair of the node name and node children.

Your program takes as input a nested list of pairs, and should output a pretty tree.

Examples:

Here are four example test cases below

["stump",[]]

["trunk",[["branch",[["leaf",[]],["leaf",[]]]],["branch",[]]]]

[".",[["bin",[]],["usr",[["bin",[]],["local",[["bin",[]],["lib",[]]]]]]]]

["kingdom",[["mineral",[]],["animal",[["dog",[["schnauzer",[]],["whippet",[]]]]]],["vegetable",[["cabbage",[]]]]]]

And these are the corresponding outputs

1

stump

2

trunk
├── branch
│   ├── leaf
│   └── leaf
└── branch

3

.
├── bin
└── usr
    ├── bin
    └── local
        ├── bin
        └── lib

4

kingdom
├── mineral
├── animal
│   └── dog
│       ├── schnauzer
│       └── whippet
└── vegetable
    └── cabbage

Notes:

  • If the characters , , , are not conveniently available in your language, you may substitute with the ASCII characters |, +, L, - respectively.

  • You may assume there is one unique root node. You may assume the input will be "nice", it doesn't matter what your program does if the input is not well-formed.

  • To avoid unfair advantages to any particular language, some flexibility in the input format is allowed within reason. For example, specifying the nesting with parens () or braces {} is OK. If it's more convenient for the node labels to be integers instead of strings, that's OK. Extra whitespace in the input is OK, as long as it's not being used to define structure. If you take the input as a string literal and parse it directly, that's OK.

  • No messing with the underlying structure of the tree! E.g., you may not change how a leaf node is represented.

  • Tip: the representation used in the examples is valid json, so you can paste it into a json linter to better see the nesting.

Scoring:

This is code golf, shortest code wins.

\$\endgroup\$
  • \$\begingroup\$ Closely related. (Same output, different input.) \$\endgroup\$ – Martin Ender Nov 22 '16 at 21:47
  • \$\begingroup\$ I'm not a regular on this site, if you think the question can be improved please comment or edit directly. Thanks! \$\endgroup\$ – wim Nov 22 '16 at 21:47
  • \$\begingroup\$ what is the exact input format? Is it a string or an object? \$\endgroup\$ – Ludonope Nov 22 '16 at 22:00
  • \$\begingroup\$ @Ludonope Whatever makes your code easier. See note 3. I expect most people will use an object, because writing a parser is probably not fun, but I don't want to discourage any possible interesting stack based approaches. \$\endgroup\$ – wim Nov 22 '16 at 22:07
  • 1
    \$\begingroup\$ The characters │, ├, └, ─ are conveniently available in most languages, but each one requires 3 bytes in UTF8, so using the ASCII gives a better score \$\endgroup\$ – edc65 Nov 24 '16 at 16:02
3
\$\begingroup\$

Haskell, 159 bytes

With preprocessing of the input to fit the defined tree datatype (included in score) since trees can't be represented as a nested list.

data T=T[Char][T]
r=reverse;z=zipWith;a%b=a:cycle[b]
p(T s b)|k<-r$p<$>b=s:(concat$r$z(z(++))(("└── "%"    ")%("├── "%"│   "))k)
mapM putStrLn.p

Usage:

> mapM putStrLn.p $ T"kingdom"[T"mineral"[],T"animal"[T"dog"[T"schnauzer"[],T"whippet"[]]],T"vegetable"[T"cabbage"[]]]
kingdom
├── mineral
├── animal
│   └── dog
│       ├── schnauzer
│       └── whippet
└── vegetable
    └── cabbage
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 123 125 bytes

Using 5 unicode graphic character, 3 bytes each. The char count is 115.

x=>(o=x[0],r=(l,p)=>l[0]&&l.map((x,i)=>r(x[1],p+'│ '[q=+!l[i+1]]+'   ',o+=`
${p+'├└'[q]}── `+x[0])),r(x[1],''),o)

Less golfed

l=>(
  o = l[0],
  r = (l,p)=> // recursive tree printer
      l[0] && 
      l.map((x,i)=>
             (
               q = +!l[i+1],
               o += `\n${p+'├└'[q]}── ` + x[0],
               r(x[1], p+'│ '[q]+'   ')
             )
      ), 
  r(l[1],''),
  o
)

F=
x=>(o=x[0],r=(l,p)=>l[0]&&l.map((x,i)=>r(x[1],p+'│ '[q=+!l[i+1]]+'   ',o+=`
${p+'├└'[q]}── `+x[0])),r(x[1],''),o)

out=x=>O.textContent+=x+'\n\n'

;[["stump",[]]
,["trunk",[["branch",[["leaf",[]],["leaf",[]]]],["branch",[]]]]
,[".",[["bin",[]],["usr",[["bin",[]],["local",[["bin",[]],["lib",[]]]]]]]]
,["kingdom",[["mineral",[]],["animal",[["dog",[["schnauzer",[]],["whippet",[]]]]]],["vegetable",[["cabbage",[]]]]]]
].forEach(t=>out(JSON.stringify(t)+'\n'+F(t)))
<pre id=O></pre>

\$\endgroup\$
1
\$\begingroup\$

Python 2, 118 119 bytes

def f(x,q='',p='',r=''):
 m,w=x;l=len(w);print q+r+m
 for i in range(l):a=l-i>1;f(w[i],q+p,' |'[a]+'   ','L+'[a]+'-- ')

Call as:

f(["kingdom",[["mineral",[]],["animal",[["dog",[["schnauzer",[]],["whippet",[]]]]]],["vegetable",[["cabbage",[]]]]]])

Outputs:

kingdom
+-- mineral
+-- animal
|   L-- dog
|       +-- schnauzer
|       L-- whippet
L-- vegetable
    L-- cabbage
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.