Skip to content

Instantly share code, notes, and snippets.

@koraa
Created August 24, 2017 18:02
Show Gist options
  • Save koraa/281efa95d4cbaafb4ec10586da29c9a9 to your computer and use it in GitHub Desktop.
Save koraa/281efa95d4cbaafb4ec10586da29c9a9 to your computer and use it in GitHub Desktop.
/// Recursively flatten an iterator and return
/// Args:
/// seq – The sequence to flatten
/// predicate – A function that is applied to each element in seq
/// to determine whether that element should also be flattened.
/// `(val) => val instanceof Array` would only flatten arrays, while
/// `(val) => val[Symbol.iterator] !== undefined` would flatten any
/// iterable, but should never be used because it will cause an infinite
/// loop flattening strings (strings are sequences of single char strings
/// which are sequences of itself...).
const recursiveFlatten = function*(seq, predicate) {
if (!predicate(seq)) {
yield seq;
return;
}
for (const sub of seq)
// yield from ... but js has no yield from
for (elm of recursiveFlatten(sub, predicate))
yield elm;
}
/// Save version of instanceof (can deal with null, undefined and primitive types)
const isInstance = (x, t) => {
if (x === null || x === undefined || t === null || t === undefined) {
return false;
} else {
return x instanceof t || x.constructor === t;
}
};
/// Throws an error if the input is falsy
const assert = (predicate) => {
if (!predicate) throw Error("Assertation Error!");
}
/// Compare the contents of two iterable sequences
const itrEq = (a, b) => {
const bit = b[Symbol.iterator]();
for (const val of a) {
const next = bit.next();
if (next.done || val !== next.value)
return false;
}
return true;
};
const test = () => {
assert(isInstance(new String(), String));
assert(isInstance("", String));
assert(!isInstance(null, String));
assert(itrEq([], []));
assert(itrEq(['a', 2], ['a', 2]));
assert(!itrEq(['b'], []));
const arrayFlatten = (seq) =>
recursiveFlatten(seq, (val) => val instanceof Array);
assert(itrEq(arrayFlatten([[1,2,[3]],4]), [1,2,3,4]));
assert(itrEq(arrayFlatten([[], [], [[]]]), []));
assert(itrEq(arrayFlatten([]), []));
const flatStr = (seq) =>
recursiveFlatten(seq, (val) =>
!isInstance(val, String) && val[Symbol.iterator] !== undefined);
// Test one other predicate
assert(itrEq(flatStr(['foo', ['bar'], new Set(['baz'])]), ['foo', 'bar', 'baz']));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment