Skip to content

Instantly share code, notes, and snippets.

@0x1b-xyz
Last active December 31, 2015 02:49
Show Gist options
  • Select an option

  • Save 0x1b-xyz/7923448 to your computer and use it in GitHub Desktop.

Select an option

Save 0x1b-xyz/7923448 to your computer and use it in GitHub Desktop.
Print a hierarchical tree from a direct relationship model
class Tree {
private model = new HashMap<String, Set<String>>()
void add(String node, String dep) {
if (!model[node])
model[node] = new HashSet<String>();
model[node] << dep
}
/**
* Finds each node with no incoming edges and treats it as a root of the printed tree.
*/
String toString() {
def buf = new StringBuilder()
model.keySet().findAll { node -> !model.values().find { deps -> deps.contains(node)} }
.each { node ->
render(buf, true, node, '', '')
}
buf.toString()
}
private void render(Stack<String> ancestry = [], StringBuilder buf,
boolean isRoot, String node, String lead, String tick) {
def isCyclic = ancestry.contains(node)
buf.append("${lead}${tick}${isRoot ? '' : '_ '}${node}${isCyclic ? ' *' : ''}\n")
if (isCyclic) return;
def deps = model[node]
if (deps)
ancestry.push(node)
else return
def spacing = isRoot ? lead : "${lead} "
deps.sort().eachWithIndex { String dep, int i ->
def isLast = (i == (deps.size() - 1))
render(ancestry, buf, false, dep,
isLast ? spacing : "${spacing}|",
isLast && isRoot ? '|' : isLast ? '\\' : '')
}
for (def ancestor; ancestor != node; ancestor = ancestry.pop());
}
}
/**
* A->B format
*/
Tree load(String edges) {
new Tree().with {
edges.eachLine { link ->
if (!link) return;
(link =~ /([\w]++)->([\w]++)/).with { matcher ->
if (!matcher.matches())
throw new IOException("Invalid input line: ${link}")
add(matcher.group(1), matcher.group(2))
}
}
it
}
}
def ex1 = load('''
A->B
A->C
B->C
B->D
''')
println ex1
println ''
def pr1 = '''A
|_ B
| |_ C
| \\_ D
|_ C
'''
assert ex1.toString().equals(pr1)
def ex2 = load('''
A->B
A->C
B->C
B->D
C->B
D->B
D->C
''')
println ex2
println ''
def pr2 = '''A
|_ B
| |_ C
| | \\_ B *
| \\_ D
| |_ B *
| \\_ C
| \\_ B *
|_ C
\\_ B
|_ C *
\\_ D
|_ B *
\\_ C *
'''
assert ex2.toString().equals(pr2)
def ex3 = load('''
A->B
A->J
B->C
B->D
C->E
D->F
D->G
D->J
E->H
E->M
F->H
H->L
I->O
I->P
I->K
J->I
J->Q
K->N
K->L
L->I
M->N
M->H
O->P
P->Q
''')
println ex3
def pr3 = '''A
|_ B
| |_ C
| | \\_ E
| | |_ H
| | | \\_ L
| | | \\_ I
| | | |_ K
| | | | |_ L *
| | | | \\_ N
| | | |_ O
| | | | \\_ P
| | | | \\_ Q
| | | \\_ P
| | | \\_ Q
| | \\_ M
| | |_ H
| | | \\_ L
| | | \\_ I
| | | |_ K
| | | | |_ L *
| | | | \\_ N
| | | |_ O
| | | | \\_ P
| | | | \\_ Q
| | | \\_ P
| | | \\_ Q
| | \\_ N
| \\_ D
| |_ F
| | \\_ H
| | \\_ L
| | \\_ I
| | |_ K
| | | |_ L *
| | | \\_ N
| | |_ O
| | | \\_ P
| | | \\_ Q
| | \\_ P
| | \\_ Q
| |_ G
| \\_ J
| |_ I
| | |_ K
| | | |_ L
| | | | \\_ I *
| | | \\_ N
| | |_ O
| | | \\_ P
| | | \\_ Q
| | \\_ P
| | \\_ Q
| \\_ Q
|_ J
|_ I
| |_ K
| | |_ L
| | | \\_ I *
| | \\_ N
| |_ O
| | \\_ P
| | \\_ Q
| \\_ P
| \\_ Q
\\_ Q
'''
assert ex3.toString().equals(pr3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment