From 56526e6f340bd6139c21639c91171d33c068ab50 Mon Sep 17 00:00:00 2001 From: Ely De La Cruz <603428+elycruz@users.noreply.github.com> Date: Sun, 28 Aug 2022 11:17:01 -0400 Subject: [PATCH] issue-#43,#61 - Updated 'Slice' type to include 'string', "and", 'T[]' - Makes type more flexible. - Updated 'group', 'groupBy', 'intercalate', and 'intersperse' types, to allow 'Slice' type. - Updated tests for, the above, and 'concatMap'. --- packages/fjl/src/list/concat.ts | 5 ++-- packages/fjl/src/list/group.ts | 3 ++- packages/fjl/src/list/groupBy.ts | 29 ++++++++++++--------- packages/fjl/src/list/intercalate.ts | 11 +++++--- packages/fjl/src/list/intersperse.ts | 27 ++++++++++--------- packages/fjl/src/types/data.ts | 8 +++--- packages/fjl/tests/list/test-concatMap.ts | 26 ++++++++++-------- packages/fjl/tests/list/test-group.ts | 13 +++++---- packages/fjl/tests/list/test-groupBy.ts | 4 +-- packages/fjl/tests/list/test-intercalate.ts | 15 ++++++++--- packages/fjl/tests/list/test-intersperse.ts | 14 +++++++++- 11 files changed, 93 insertions(+), 62 deletions(-) diff --git a/packages/fjl/src/list/concat.ts b/packages/fjl/src/list/concat.ts index a41133d4..faac718b 100644 --- a/packages/fjl/src/list/concat.ts +++ b/packages/fjl/src/list/concat.ts @@ -4,8 +4,7 @@ import {Slice} from "../types"; export const /** - * Concatenates all the elements of a container of lists. + * Concatenates all the elements of a "container of lists". */ - concat = >(xs: TS[]): TS => - append(...xs) as TS + concat = (xss: Slice | Slice[]) => append(...xss) ; diff --git a/packages/fjl/src/list/group.ts b/packages/fjl/src/list/group.ts index 02e764ec..143c22b1 100644 --- a/packages/fjl/src/list/group.ts +++ b/packages/fjl/src/list/group.ts @@ -1,5 +1,6 @@ import {groupBy} from "./groupBy"; import {equal} from "../boolean"; +import {Slice} from "../types"; /** * The group function takes a list and returns a list of lists such that @@ -10,4 +11,4 @@ import {equal} from "../boolean"; * group("Mississippi".slice(0)) === [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], "i"] * ``` */ -export const group = (xs: T[]): T[][] => groupBy(equal, xs); +export const group = (xs: Slice): Slice[] => groupBy(equal, xs); diff --git a/packages/fjl/src/list/groupBy.ts b/packages/fjl/src/list/groupBy.ts index d1e49771..23e46b91 100644 --- a/packages/fjl/src/list/groupBy.ts +++ b/packages/fjl/src/list/groupBy.ts @@ -1,4 +1,5 @@ import {BinaryPred, Slice} from "../types"; +import {of} from "../object"; export const @@ -10,27 +11,29 @@ export const * [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], "i"] * ``` */ - groupBy = (equalityOp: BinaryPred, xs: TS): T[][] => { + groupBy = (equalityOp: BinaryPred, xs: Slice): Slice[] => { if (!xs) return []; - const limit = xs.length; + const limit = xs.length, + groupIsArray = Array.isArray(xs); - if (!limit) return [[]]; + // Initialize variables for tracking + let prevItem = xs[0], + group = of(xs, prevItem); - // Groupings - const groups: T[][] = []; + if (!limit) return [group]; - // Initialize variables for tracking - let prevItem = xs[0] as T, - group: T[] = [prevItem]; + // Groupings + const groups: Slice[] = []; // Group remainder of items for (let ind = 1; ind < limit; ind += 1) { - const x = xs[ind] as T; + const x = xs[ind]; // If equality check passed group item, and continue to next if (equalityOp(x, prevItem)) { - group.push(x); + if (groupIsArray) (group as T[]).push(x); + else group = group.concat(x); prevItem = x; continue; } @@ -38,7 +41,7 @@ export const // Items for previous group 'grouped'. Move to next group. groups.push(group); prevItem = x; - group = [x]; + group = of(group, x); } // Push last group @@ -50,8 +53,8 @@ export const /** * Curried version of `$groupBy`. */ - $groupBy = (equalityOp: BinaryPred) => - (xs: TS): T[][] => groupBy(equalityOp, xs) + $groupBy = (equalityOp: BinaryPred) => + (xs: Slice): Slice[] => groupBy(equalityOp, xs) ; diff --git a/packages/fjl/src/list/intercalate.ts b/packages/fjl/src/list/intercalate.ts index 652d77df..a3ff6415 100644 --- a/packages/fjl/src/list/intercalate.ts +++ b/packages/fjl/src/list/intercalate.ts @@ -1,5 +1,6 @@ import {intersperse} from "./intersperse"; import {concat} from "./concat"; +import {Slice} from "../types"; export const @@ -8,9 +9,11 @@ export const * It inserts the list `xs` in between the lists in `xss` and concatenates * the result. */ - intercalate = (xs: TS, xss: TS[]): TS => - concat(intersperse(xs, xss)), + intercalate = (xs: Slice, xss: Slice[]): Slice => { + const rslt = intersperse(xs, xss); + return !rslt.length ? rslt : concat(rslt); + }, - $intercalate = (xs: TS) => - (xss: TS[]): TS => intercalate(xs, xss) + $intercalate = (xs: Slice) => + (xss: Slice[]): Slice => intercalate(xs, xss) ; diff --git a/packages/fjl/src/list/intersperse.ts b/packages/fjl/src/list/intersperse.ts index b8f53000..c5f1d1f6 100644 --- a/packages/fjl/src/list/intersperse.ts +++ b/packages/fjl/src/list/intersperse.ts @@ -1,28 +1,31 @@ +import {Slice} from "../types"; +import {of} from "../object"; + export const /** * Takes an element and a list and `intersperses' that element between the * elements of the list. */ - intersperse = (between: T, xs: TS): T[] => { - if (!xs || !xs.length) { - return []; - } - const limit = xs.length, + intersperse = (between: T, xs: Slice): Slice => { + const limit = xs.length; + if (!limit) return of(xs); + const isArrayXs = Array.isArray(xs), lastInd = limit - 1; - let i = 0; - const out = [] as T[]; - for (; i < limit; i += 1) { + let out = of(xs); + for (let i = 0; i < limit; i += 1) { if (i === lastInd) { - out.push(xs[i] as T); + if (isArrayXs) (out as T[]).push(xs[i]); + else out = out.concat(xs[i]); } else { - out.push(xs[i] as T, between); + if (isArrayXs) (out as T[]).push(xs[i], between); + else out = out.concat(xs[i], between as unknown as any); } } return out; }, - $intersperse = (between: T) => - (xs: TS): T[] => intersperse(between, xs) + $intersperse = (between: T) => + (xs: Slice): Slice => intersperse(between, xs) ; diff --git a/packages/fjl/src/types/data.ts b/packages/fjl/src/types/data.ts index faa1a017..df29907e 100644 --- a/packages/fjl/src/types/data.ts +++ b/packages/fjl/src/types/data.ts @@ -73,7 +73,7 @@ export type ArrayTypeConstructor = ArrayConstructor | interface SliceBase { readonly length: number; - slice(start: number, end?: number); + slice(start: number, end?: number): typeof this; indexOf(x, position: number): number; @@ -83,9 +83,9 @@ interface SliceBase { } /** - * `Union + Sum` Slice type - Represents, the intersection, of strings, arrays, and custom structures that meet it's requirements. + * `Union + Sum` Slice type - Represents, the intersection, of the string, array, and custom structure, types that match the `Slice` "summed" interfaces. */ -export type Slice = SliceBase & { +export type Slice = string | T[] | (SliceBase & { [Symbol.iterator](): IterableIterator; } & ({ [index: number]: any @@ -95,7 +95,7 @@ export type Slice = SliceBase & { readonly [index: number]: string; concat(...xss: string[]): typeof this; -}); +})); export type SliceConstructor = StringConstructor | ArrayConstructor; diff --git a/packages/fjl/tests/list/test-concatMap.ts b/packages/fjl/tests/list/test-concatMap.ts index 502cf091..d346dff2 100644 --- a/packages/fjl/tests/list/test-concatMap.ts +++ b/packages/fjl/tests/list/test-concatMap.ts @@ -1,18 +1,22 @@ -import {alphabetArray, alphabetCharCodeRange} from "../helpers"; +import {alphabetArray, alphabetCharCodeRange, vowelCharCodes, vowelsArray} from "../helpers"; import {concatMap} from "../../src/list/concatMap"; +import {id} from "../../src"; describe('#concatMap', () => { - const id = (x: any): any => x; + const charCodeToCharOp = (charCode: number) => String.fromCharCode(charCode); - it('should map a function on a list and concatenate lists in resulting list into a list.', () => { - const charCodeToCharOp = (charCode: number): string => String.fromCharCode(charCode); - expect(concatMap(charCodeToCharOp, alphabetCharCodeRange.map(c => [c]))).toEqual(alphabetArray); - }); - - it('should return an empty list when receiving an empty list or a list of empty lists', () => { - expect(concatMap(id, [])).toEqual([]); - expect(concatMap(id, [[], [], []])).toEqual([]); - }); + (<[Parameters, ReturnType][]>[ + [[id, []], []], + [[id, [], [], []], []], + [[charCodeToCharOp, vowelCharCodes.map(c => [c])], vowelsArray] + ]) + .forEach(([args, expected]) => { + it(`concatMap(${args[0].name}, ${JSON.stringify(args[1])}) === ` + + `${JSON.stringify(expected)}`, function () { + const result = concatMap(...args); + expect(result).toEqual(expected); + }); + }); it('should throw an error when receiving `undefined` or `null` in it\'s list position', () => { expect(() => concatMap(id, null)).toThrow(); diff --git a/packages/fjl/tests/list/test-group.ts b/packages/fjl/tests/list/test-group.ts index b57e994e..9d606282 100644 --- a/packages/fjl/tests/list/test-group.ts +++ b/packages/fjl/tests/list/test-group.ts @@ -6,14 +6,13 @@ describe(`#group`, () => { mississippiArray = mississippi.split(''), mississippiResult = [['M'], ['i'], ['s', 's'], ['i'], ['s', 's'], ['i'], ['p', 'p'], ['i']]; (<[Parameters, ReturnType][]>[ - [[vowelsArray], vowelsArray.map(x => [x])], - [[vowelsString], vowelsArray.map(x => [x])], - [[mississippi], [mississippiResult]], - [[mississippiArray], mississippiResult] - ]).forEach(([xs, expected]) => { - it(`group(${JSON.stringify(xs)}) === ${JSON.stringify(expected)}`, () => { + [[vowelsArray], vowelsArray.map(x => [x])], + [[vowelsString], vowelsArray], + [[mississippi], mississippiResult.map(xs => xs.join(''))], + [[mississippiArray], mississippiResult] + ]).forEach(([[xs], expected]) => { + it(`group(${JSON.stringify(xs.valueOf())}) === ${JSON.stringify(expected)}`, () => { expect(group(xs)).toEqual(expected); }); }); }); - diff --git a/packages/fjl/tests/list/test-groupBy.ts b/packages/fjl/tests/list/test-groupBy.ts index cefbac2b..237ded57 100644 --- a/packages/fjl/tests/list/test-groupBy.ts +++ b/packages/fjl/tests/list/test-groupBy.ts @@ -7,8 +7,8 @@ describe('#groupBy', () => { mississippiResult = [['M'], ['i'], ['s', 's'], ['i'], ['s', 's'], ['i'], ['p', 'p'], ['i']]; (<[Parameters, ReturnType][]>[ [[equal, vowelsArray], vowelsArray.map(x => [x])], - [[equal, vowelsString], vowelsArray.map(x => [x])], - [[equal, mississippi], mississippiResult], + [[equal, vowelsString], vowelsArray], + [[equal, mississippi], mississippiResult.map(xs => xs.join(''))], [[equal, mississippiArray], mississippiResult], [[equal, alphabetArray], alphabetArray.map(char => [char])] ]).forEach(([[pred, xs], expected]) => { diff --git a/packages/fjl/tests/list/test-intercalate.ts b/packages/fjl/tests/list/test-intercalate.ts index 4b17b90d..24827010 100644 --- a/packages/fjl/tests/list/test-intercalate.ts +++ b/packages/fjl/tests/list/test-intercalate.ts @@ -1,16 +1,23 @@ import {intercalate} from "../../src/list/intercalate"; -import {alphabetArray} from "../helpers"; +import {vowelsArray, vowelsString} from "../helpers"; const {stringify} = JSON; describe('#intercalate', () => { type Intercalate = typeof intercalate; - const charArrayArray = alphabetArray.map(x => [x]); + const vowelsArrayArray = vowelsArray.map(x => [x]), + vowelsStringWithCommas = vowelsArray.join(','), + vowelsArrayWithCommas = vowelsArray.flatMap((x, i) => i > 0 ? [',', x] : [x]) + ; (<[Parameters, ReturnType][]>[ - [[',', charArrayArray], charArrayArray.map(xs => xs[0]).join(',').split('')], - [[[','], charArrayArray], charArrayArray.map(xs => xs[0]).join(',').split('')], + [[',', vowelsArray], vowelsStringWithCommas], + [[[','], vowelsArrayArray], vowelsArrayWithCommas], + [[',', vowelsString], vowelsStringWithCommas], [[',', ['a']], 'a'], [[[','], ['a']], 'a'], + [['', vowelsString], vowelsString], + [['', vowelsArray], vowelsString], + [['', ''], ''], [['', []], []], [['', [[]]], []], [[[''], []], []], diff --git a/packages/fjl/tests/list/test-intersperse.ts b/packages/fjl/tests/list/test-intersperse.ts index fefcfdf6..f76e152d 100644 --- a/packages/fjl/tests/list/test-intersperse.ts +++ b/packages/fjl/tests/list/test-intersperse.ts @@ -6,7 +6,19 @@ describe('#intersperse', () => { (<[Parameters, ReturnType][]>[ [[',', alphabetArray], alphabetArray.join(',').split('')], [[',', ['a']], ['a']], - [['', []], []] + [['', []], []], + [['', ''], ''], + [['a', []], []], + [['a', ''], ''], + [[[','], alphabetArray], + alphabetArray.flatMap((x, i) => + i !== 0 ? [[','], x] : [x]) + ], + [[[','], ['a']], ['a']], + [[[''], []], []], + [[[''], ''], ''], + [[['a'], []], []], + [[['a'], ''], ''], ]) .forEach(([args, expected]) => { it('', () => {