From 8b68ea933293cd160e5584bfe4e24c56ccacc01a Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Sun, 30 Jul 2017 14:54:58 +0300 Subject: [PATCH] Add arrayDeep and newArrayDeep functions Like array and newArray but applied recursively --- src/functions/arrayDeep.js | 86 +++++++++++++++++++++++++++++++++ src/functions/newArrayDeep.js | 90 +++++++++++++++++++++++++++++++++++ src/higher.js | 2 + 3 files changed, 178 insertions(+) create mode 100644 src/functions/arrayDeep.js create mode 100644 src/functions/newArrayDeep.js diff --git a/src/functions/arrayDeep.js b/src/functions/arrayDeep.js new file mode 100644 index 0000000..6d89012 --- /dev/null +++ b/src/functions/arrayDeep.js @@ -0,0 +1,86 @@ +import {isSequence} from "../core/sequence"; +import {wrap} from "../core/wrap"; + +import {array} from "./array"; + +import {NotBoundedError} from "../errors/NotBoundedError"; + +export const arrayDeep = wrap({ + name: "arrayDeep", + summary: "Recursively acquire an in-memory array from a sequence potentially containing more sequences.", + docs: process.env.NODE_ENV !== "development" ? undefined : { + introduced: "higher@1.0.0", + expects: (` + The function expects a single known-bounded sequence as input. + `), + returns: (` + The function returns an array containing the elements of the input + sequence. Elements of that input sequence that were known-bounded + arrays also recursively have the operation applied to them, such + that a sequence of sequences becomes an array of arrays, and so on. + /Sequences which directly represent the contents of an in-memory + array will have that source array given as output. + To always acquire a new array object that is guaranteed to be safe + to modify, use @newArrayDeep. + `), + examples: [ + "basicUsage", + ], + related: [ + "array", "newArray", "newArrayDeep", + ], + }, + attachSequence: true, + async: true, + arguments: { + one: wrap.expecting.sequence, + }, + implementation: (source) => { + NotBoundedError.enforce(source, { + message: "Failed to create array from sequence.", + }); + const result = array(source); + for(let i = 0; i < result.length; i++){ + if(isSequence(result[i]) && result[i].bounded()){ + result[i] = arrayDeep(result[i]); + } + } + return result; + }, + tests: process.env.NODE_ENV !== "development" ? undefined : { + "basicUsage": hi => { + // This is a sequence of sequences. + const seq = hi.mapIndex(i => hi.range(i + 1)).head(3); + hi.assert(hi.isSequence(seq)); + hi.assert(hi.isSequence(seq.index(0))); + // And from it is created an array of arrays. + const array = seq.arrayDeep(); + hi.assert(hi.isArray(array)); + hi.assert(hi.isArray(array[0])); + // Which contains these numbers: + hi.assertEqual(array, [[0], [0, 1], [0, 1, 2]]); + }, + "emptyInput": hi => { + const array = hi.emptySequence().arrayDeep(); + hi.assert(hi.isArray(array)); + hi.assert(array.length === 0); + }, + "unboundedElementInInput": hi => { + const array = hi([0, hi.range(3), hi.counter()]).arrayDeep(); + hi.assert(array[0] === 0); + hi.assertEqual(array[1], [0, 1, 2]); + hi.assert(hi.isArray(array[1])); + hi.assert(hi.isSequence(array[2])); + }, + "modifyOutput": hi => { + const array = [[0, 1, 2]]; + const output = hi.arrayDeep(array); + output[0][0] = 10; + hi.assertEqual(output, [[10, 1, 2]]); + // Input is modified + hi.assertEqual(array, [[10, 1, 2]]); + }, + }, +}); + +export default arrayDeep; diff --git a/src/functions/newArrayDeep.js b/src/functions/newArrayDeep.js new file mode 100644 index 0000000..940e213 --- /dev/null +++ b/src/functions/newArrayDeep.js @@ -0,0 +1,90 @@ +import {isSequence} from "../core/sequence"; +import {isArray} from "../core/types"; +import {wrap} from "../core/wrap"; + +import {newArray} from "./newArray"; + +import {NotBoundedError} from "../errors/NotBoundedError"; + +export const newArrayDeep = wrap({ + name: "newArrayDeep", + summary: "Recursively acquire an in-memory array from a sequence potentially containing more sequences.", + docs: process.env.NODE_ENV !== "development" ? undefined : { + introduced: "higher@1.0.0", + expects: (` + The function expects a single known-bounded sequence as input. + `), + returns: (` + The function returns an array containing the elements of the input + sequence. Elements of that input sequence that were known-bounded + arrays also recursively have the operation applied to them, such + that a sequence of sequences becomes an array of arrays, and so on. + /Sequences which directly represent the contents of an in-memory + array will have a copy of that array given as output. + If it is not necessary to preserve the original arrays in case of + modification, or if the output of this function will not be + modified, then it will be more efficient to call @arrayDeep instead. + `), + examples: [ + "basicUsage", + ], + related: [ + "array", "newArray", "arrayDeep", + ], + }, + attachSequence: true, + async: true, + arguments: { + one: wrap.expecting.sequence, + }, + implementation: (source) => { + NotBoundedError.enforce(source, { + message: "Failed to create array from sequence.", + }); + const result = newArray(source); + for(let i = 0; i < result.length; i++){ + if(isSequence(result[i]) && result[i].bounded()){ + result[i] = newArrayDeep(result[i]); + }else if(isArray(result[i])){ + result[i] = result[i].slice(); + } + } + return result; + }, + tests: process.env.NODE_ENV !== "development" ? undefined : { + "basicUsage": hi => { + // This is a sequence of sequences. + const seq = hi.mapIndex(i => hi.range(i + 1)).head(3); + hi.assert(hi.isSequence(seq)); + hi.assert(hi.isSequence(seq.index(0))); + // And from it is created an array of arrays. + const array = seq.newArrayDeep(); + hi.assert(hi.isArray(array)); + hi.assert(hi.isArray(array[0])); + // Which contains these numbers: + hi.assertEqual(array, [[0], [0, 1], [0, 1, 2]]); + }, + "emptyInput": hi => { + const array = hi.emptySequence().newArrayDeep(); + hi.assert(hi.isArray(array)); + hi.assert(array.length === 0); + }, + "unboundedElementInInput": hi => { + const array = hi([0, hi.range(3), hi.counter()]).newArrayDeep(); + hi.assert(array[0] === 0); + hi.assertEqual(array[1], [0, 1, 2]); + hi.assert(hi.isArray(array[1])); + hi.assert(hi.isSequence(array[2])); + }, + "modifyOutput": hi => { + const array = [[0, 1, 2]]; + const output = hi.newArrayDeep(array); + output[0][0] = 10; + hi.assertEqual(output, [[10, 1, 2]]); + // Input is not modified + hi.assertEqual(array, [[0, 1, 2]]); + }, + }, +}); + +export default newArrayDeep; diff --git a/src/higher.js b/src/higher.js index 2f7c67c..0116399 100644 --- a/src/higher.js +++ b/src/higher.js @@ -173,6 +173,7 @@ import {anyPass} from "./functions/anyPass"; hi.register(anyPass); import {all} from "./functions/all"; hi.register(all); import {allPass} from "./functions/allPass"; hi.register(allPass); import {array} from "./functions/array"; hi.register(array); +import {arrayDeep} from "./functions/arrayDeep"; hi.register(arrayDeep); import {assumeBounded} from "./functions/assumeBounded"; hi.register(assumeBounded); import {benchmark} from "./functions/benchmark"; hi.register(benchmark); import {bigrams} from "./functions/bigrams"; hi.register(bigrams); @@ -219,6 +220,7 @@ import {max} from "./functions/max"; hi.register(max); import {min} from "./functions/min"; hi.register(min); import {negate} from "./functions/negate"; hi.register(negate); import {newArray} from "./functions/newArray"; hi.register(newArray); +import {newArrayDeep} from "./functions/newArrayDeep"; hi.register(newArrayDeep); import {newObject} from "./functions/newObject"; hi.register(newObject); import {ngrams} from "./functions/ngrams"; hi.register(ngrams); import {none} from "./functions/none"; hi.register(none);