Created
August 24, 2017 18:02
-
-
Save koraa/281efa95d4cbaafb4ec10586da29c9a9 to your computer and use it in GitHub Desktop.
This file contains 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
/// 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