Visualize a tree: Difference between revisions
Content added Content deleted
m (→Python :: Functional composition: (edited a comment line)) |
(→JS Plain text: Updated the decorated-outline version with an option to prune out nodeless lines) |
||
Line 1,297: | Line 1,297: | ||
===Plain text=== |
===Plain text=== |
||
====Decorated outline==== |
|||
<lang JavaScript>(() => { |
<lang JavaScript>(() => { |
||
'use strict'; |
'use strict'; |
||
// drawTree :: Bool -> Tree String -> String |
|||
const main = () => |
|||
const drawTree = blnCompact => tree => { |
|||
drawTree(dctTree); |
|||
// Simple decorated-outline style of ascii tree drawing, |
|||
// with nodeless lines pruned out if blnCompact is True. |
|||
const xs = draw(tree); |
|||
return unlines( |
|||
blnCompact ? ( |
|||
xs.filter( |
|||
s => s.split('') |
|||
.some(c => !' │'.includes(c)) |
|||
) |
|||
) : xs |
|||
); |
|||
}; |
|||
// draw :: Tree String -> [String] |
// draw :: Tree String -> [String] |
||
Line 1,331: | Line 1,344: | ||
}; |
}; |
||
// TEST ----------------------------------------------- |
|||
// drawTree :: Tree String -> String |
|||
const |
const main = () => { |
||
const tree = Node( |
|||
'Alpha', [ |
|||
Node('Beta', [ |
|||
Node('Epsilon', []), |
|||
Node('Zeta', []), |
|||
Node('Eta', []) |
|||
]), |
|||
Node('Gamma', [Node('Theta', [])]), |
|||
Node('Delta', [ |
|||
Node('Iota', []), |
|||
Node('Kappa', []), |
|||
Node('Lambda', []) |
|||
]) |
|||
]); |
|||
return [true, false] |
|||
.map(blnCompact => drawTree(blnCompact)(tree)) |
|||
const dctTree = { |
|||
.join('\n\n'); |
|||
"root": "alpha", |
|||
"nest": [{ |
|||
"type": "Node", |
|||
"root": "beta", |
|||
"nest": [{ |
|||
"type": "Node", |
|||
"root": "gamma", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "epsilon", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "eta", |
|||
"nest": [] |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "iota", |
|||
"nest": [{ |
|||
"type": "Node", |
|||
"root": "kappa", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "mu", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "xi", |
|||
"nest": [] |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "pi", |
|||
"nest": [{ |
|||
"type": "Node", |
|||
"root": "rho", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "tau", |
|||
"nest": [] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "phi", |
|||
"nest": [] |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"type": "Node", |
|||
"root": "psi", |
|||
"nest": [] |
|||
} |
|||
] |
|||
}; |
}; |
||
// GENERIC FUNCTIONS ---------------------------- |
|||
// GENERIC FUNCTIONS ---------------------------------- |
|||
// Node :: a -> [Tree a] -> Tree a |
|||
const Node = (v, xs) => ({ |
|||
type: 'Node', |
|||
root: v, // any type of value (consistent across tree) |
|||
nest: xs || [] |
|||
}); |
|||
// append (++) :: [a] -> [a] -> [a] |
// append (++) :: [a] -> [a] -> [a] |
||
// append (++) :: String -> String -> String |
// append (++) :: String -> String -> String |
||
const append = (xs, ys) => xs.concat(ys); |
const append = (xs, ys) => xs.concat(ys); |
||
// chars :: String -> [Char] |
|||
const chars = s => s.split(''); |
|||
// cons :: a -> [a] -> [a] |
// cons :: a -> [a] -> [a] |
||
const cons = (x, xs) => |
const cons = (x, xs) => [x].concat(xs); |
||
Array.isArray(xs) ? ( |
|||
[x].concat(xs) |
|||
) : (x + xs); |
|||
// Returns Infinity over objects without finite length |
// Returns Infinity over objects without finite length. |
||
// |
// This enables zip and zipWith to choose the shorter |
||
// argument when one is non-finite, like cycle, repeat etc |
// argument when one is non-finite, like cycle, repeat etc |
||
// length :: [a] -> Int |
// length :: [a] -> Int |
||
const length = xs => |
const length = xs => |
||
(Array.isArray(xs) || 'string' === typeof xs) ? ( |
|||
xs.length |
|||
) : Infinity; |
|||
// lines :: String -> [String] |
// lines :: String -> [String] |
||
Line 1,434: | Line 1,404: | ||
length: n |
length: n |
||
}, () => x); |
}, () => x); |
||
// shift :: Int -> [a] -> [a] |
|||
const shift = (n, xs) => { |
|||
const lng = length(xs); |
|||
return Infinity > lng ? ( |
|||
take(lng, drop(n, cycle(xs))) |
|||
) : (drop(n, xs), xs); |
|||
}; |
|||
// take :: Int -> [a] -> [a] |
// take :: Int -> [a] -> [a] |
||
// take :: Int -> String -> String |
|||
const take = (n, xs) => |
const take = (n, xs) => |
||
xs.slice(0, n); |
|||
xs.constructor.constructor.name !== 'GeneratorFunction' ? ( |
|||
xs.slice(0, n) |
|||
) : [].concat.apply([], Array.from({ |
|||
length: n |
|||
}, () => { |
|||
const x = xs.next(); |
|||
return x.done ? [] : [x.value]; |
|||
})); |
|||
// unlines :: [String] -> String |
// unlines :: [String] -> String |
||
Line 1,473: | Line 1,427: | ||
// MAIN --- |
// MAIN --- |
||
return main(); |
|||
return ( |
|||
// console.log(strTree), |
|||
strTree |
|||
); |
|||
})();</lang> |
})();</lang> |
||
{{Out}} |
{{Out}} |
||
<pre> |
<pre>Alpha |
||
├─ Beta |
|||
│ ├─ Epsilon |
|||
│ ├─ Zeta |
|||
│ └─ Eta |
|||
├─ Gamma |
|||
│ └─ Theta |
|||
└─ Delta |
|||
├─ Iota |
|||
├─ Kappa |
|||
└─ Lambda |
|||
Alpha |
|||
│ |
│ |
||
├─ |
├─ Beta |
||
│ │ |
│ │ |
||
│ ├─ |
│ ├─ Epsilon |
||
│ │ |
│ │ |
||
│ ├─ |
│ ├─ Zeta |
||
│ │ |
│ │ |
||
│ └─ |
│ └─ Eta |
||
│ |
│ |
||
├─ |
├─ Gamma |
||
│ │ |
|||
│ ├─ kappa |
|||
│ │ |
|||
│ ├─ mu |
|||
│ │ |
|||
│ └─ xi |
|||
│ |
|||
├─ pi |
|||
│ │ |
|||
│ ├─ rho |
|||
│ │ |
|||
│ ├─ tau |
|||
│ │ |
│ │ |
||
│ └─ |
│ └─ Theta |
||
│ |
│ |
||
└─ |
└─ Delta |
||
│ |
|||
├─ Iota |
|||
│ |
|||
├─ Kappa |
|||
│ |
|||
└─ Lambda</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |