Skip to content

Commit

Permalink
issue-#43,#61 - Updated 'Slice' type to include 'string', "and", 'T[]…
Browse files Browse the repository at this point in the history
…' - Makes type more flexible.

- Updated 'group', 'groupBy', 'intercalate', and 'intersperse' types, to allow 'Slice' type.
- Updated tests for, the above, and 'concatMap'.
  • Loading branch information
elycruz committed Aug 28, 2022
1 parent e31d52e commit 56526e6
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 62 deletions.
5 changes: 2 additions & 3 deletions packages/fjl/src/list/concat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <T, TS extends Slice<T>>(xs: TS[]): TS =>
append(...xs) as TS
concat = (xss: Slice | Slice[]) => append(...xss)
;
3 changes: 2 additions & 1 deletion packages/fjl/src/list/group.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 = <T>(xs: T[]): T[][] => groupBy(equal, xs);
export const group = <T>(xs: Slice<T>): Slice<T>[] => groupBy(equal, xs);
29 changes: 16 additions & 13 deletions packages/fjl/src/list/groupBy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {BinaryPred, Slice} from "../types";
import {of} from "../object";

export const

Expand All @@ -10,35 +11,37 @@ export const
* [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], "i"]
* ```
*/
groupBy = <T, TS extends T[]>(equalityOp: BinaryPred<T>, xs: TS): T[][] => {
groupBy = <T>(equalityOp: BinaryPred<T>, xs: Slice<T>): Slice<T>[] => {
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<T>[] = [];

// 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;
}

// Items for previous group 'grouped'. Move to next group.
groups.push(group);
prevItem = x;
group = [x];
group = of(group, x);
}

// Push last group
Expand All @@ -50,8 +53,8 @@ export const
/**
* Curried version of `$groupBy`.
*/
$groupBy = <T, TS extends T[]>(equalityOp: BinaryPred<T>) =>
(xs: TS): T[][] => groupBy(equalityOp, xs)
$groupBy = <T>(equalityOp: BinaryPred<T>) =>
(xs: Slice<T>): Slice<T>[] => groupBy(equalityOp, xs)

;

Expand Down
11 changes: 7 additions & 4 deletions packages/fjl/src/list/intercalate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {intersperse} from "./intersperse";
import {concat} from "./concat";
import {Slice} from "../types";

export const

Expand All @@ -8,9 +9,11 @@ export const
* It inserts the list `xs` in between the lists in `xss` and concatenates
* the result.
*/
intercalate = <T, TS extends T[]>(xs: TS, xss: TS[]): TS =>
concat(intersperse(xs, xss)),
intercalate = <T>(xs: Slice<T>, xss: Slice<T>[]): Slice<T> => {
const rslt = intersperse(xs, xss);
return !rslt.length ? rslt : concat(rslt);
},

$intercalate = <T, TS extends T[]>(xs: TS) =>
(xss: TS[]): TS => intercalate(xs, xss)
$intercalate = <T>(xs: Slice<T>) =>
(xss: Slice<T>[]): Slice<T> => intercalate(xs, xss)
;
27 changes: 15 additions & 12 deletions packages/fjl/src/list/intersperse.ts
Original file line number Diff line number Diff line change
@@ -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 = <T, TS extends T[]>(between: T, xs: TS): T[] => {
if (!xs || !xs.length) {
return [];
}
const limit = xs.length,
intersperse = <T = string | any>(between: T, xs: Slice<T>): Slice<T> => {
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 = <T, TS extends T[]>(between: T) =>
(xs: TS): T[] => intersperse(between, xs)
$intersperse = <T>(between: T) =>
(xs: Slice<T>): Slice<T> => intersperse(between, xs)

;
8 changes: 4 additions & 4 deletions packages/fjl/src/types/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<T = any> = SliceBase & {
export type Slice<T = any> = string | T[] | (SliceBase & {
[Symbol.iterator](): IterableIterator<T>;
} & ({
[index: number]: any
Expand All @@ -95,7 +95,7 @@ export type Slice<T = any> = SliceBase & {
readonly [index: number]: string;

concat(...xss: string[]): typeof this;
});
}));

export type SliceConstructor = StringConstructor | ArrayConstructor;

Expand Down
26 changes: 15 additions & 11 deletions packages/fjl/tests/list/test-concatMap.ts
Original file line number Diff line number Diff line change
@@ -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<typeof concatMap>, ReturnType<typeof concatMap>][]>[
[[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();
Expand Down
13 changes: 6 additions & 7 deletions packages/fjl/tests/list/test-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ describe(`#group`, () => {
mississippiArray = mississippi.split(''),
mississippiResult = [['M'], ['i'], ['s', 's'], ['i'], ['s', 's'], ['i'], ['p', 'p'], ['i']];
(<[Parameters<typeof group>, ReturnType<typeof group>][]>[
[[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);
});
});
});

4 changes: 2 additions & 2 deletions packages/fjl/tests/list/test-groupBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ describe('#groupBy', () => {
mississippiResult = [['M'], ['i'], ['s', 's'], ['i'], ['s', 's'], ['i'], ['p', 'p'], ['i']];
(<[Parameters<GroupBy>, ReturnType<GroupBy>][]>[
[[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]) => {
Expand Down
15 changes: 11 additions & 4 deletions packages/fjl/tests/list/test-intercalate.ts
Original file line number Diff line number Diff line change
@@ -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<Intercalate>, ReturnType<Intercalate>][]>[
[[',', 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],
[['', ''], ''],
[['', []], []],
[['', [[]]], []],
[[[''], []], []],
Expand Down
14 changes: 13 additions & 1 deletion packages/fjl/tests/list/test-intersperse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@ describe('#intersperse', () => {
(<[Parameters<Intersperse>, ReturnType<Intersperse>][]>[
[[',', 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('', () => {
Expand Down

0 comments on commit 56526e6

Please sign in to comment.