Skip to content

Instantly share code, notes, and snippets.

@sonyseng
Last active December 9, 2023 08:49
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save sonyseng/c4b5fc25f357dc6c8e83 to your computer and use it in GitHub Desktop.
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)
// 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