Last active
December 9, 2023 08:49
-
-
Save sonyseng/c4b5fc25f357dc6c8e83 to your computer and use it in GitHub Desktop.
Playing around with the Iterators from ES6 to walk a tree non-recursively (babeljs)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Test tree with contrived data | |
let testTree = { | |
value: 1, | |
child: [ | |
{value: 2, child: [ | |
{value: 7, child: []}, | |
{value: 8, child: []}, | |
{value: 9, child: []}, | |
]}, | |
{value: 3, child: []}, | |
{value: 4, child: []}, | |
{value: 5, child: []}, | |
{value: 6, child: [ | |
{value: 11, child: []}, | |
{value: 12, child: []}, | |
{value: 13, child: []}, | |
{value: 14, child: []}, | |
{value: 15, child: [ | |
{value: 21, child: []}, | |
{value: 22, child: []}, | |
{value: 23, child: []}, | |
]} | |
]} | |
]}; | |
// This is the stack version of a tree traversal | |
function treeIterator (tree) { | |
// Our iterable object. This object meets needs to have a Symbol.iterator function that | |
// returns an method named next(). The next method returns and object with just two properties: | |
// a done property to signal when we can no longer iterate and a value property. | |
let iterableObject = { | |
// This is the magic iterator function | |
[Symbol.iterator] () { | |
// Keep track of the nodes in a stack | |
let nodeStack = [tree]; | |
let done = false, value; | |
return { | |
next () { | |
let node = nodeStack.pop(); | |
if (node) { | |
value = node.value; | |
// Cheating a bit here. The concat acts like a push of all the | |
// child nodes onto the stack. | |
nodeStack = nodeStack.concat(node.child); | |
} else { | |
done = true; | |
} | |
// Loving the object initialization sugar | |
return {done, value}; | |
} | |
} | |
} | |
} | |
return iterableObject; | |
} | |
// Now that the interface's contract has been met with Symbol.iterator, we can | |
// use the new for .. of syntax to traverse an iterable object. | |
for (let value of treeIterator(testTree)) { | |
console.log(value); | |
} | |
// Output should be: | |
// 1 | |
// 6 | |
// 15 | |
// 23 | |
// 22 | |
// 21 | |
// 14 | |
// 13 | |
// 12 | |
// 11 | |
// 5 | |
// 4 | |
// 3 | |
// 2 | |
// 9 | |
// 8 | |
// 7 | |
// Get the iterator out and call next() directly | |
let iterator = treeIterator(testTree)[Symbol.iterator](); | |
console.log(iterator.next()); | |
console.log(iterator.next()); | |
console.log(iterator.next()); | |
// Output should be: | |
// {"done":false,"value":1} | |
// {"done":false,"value":6} | |
// {"done":false,"value":15} | |
// Flatten the tree using the spread operator. Combined with the | |
// rest operator destructuring to play around with the items in the tree. | |
let [a, b, c, ...rest] = [...treeIterator(testTree)]; | |
console.log(a, b, c, rest); | |
// Output should be: | |
// 1 6 15 [23,22,21,14,13,12,11,5,4,3,2,9,8,7] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment