Skip to content

Commit

Permalink
style: move to the set utility
Browse files Browse the repository at this point in the history
  • Loading branch information
Anna-MariiaPetryk committed Sep 9, 2021
1 parent 2960723 commit b8828ab
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 89 deletions.
4 changes: 3 additions & 1 deletion src/modules/esl-utils/all.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Common
// Miscellanies
export * as UID from './misc/uid';
export * as SetUtils from './misc/set';
export * as ArrayUtils from './misc/array';
export * as ObjectUtils from './misc/object';
export * as FormatUtils from './misc/format';
export * as FunctionUtils from './misc/functions';

// Memoization decorator
export * from './misc/memoize';

// Common
Expand Down
47 changes: 2 additions & 45 deletions src/modules/esl-utils/misc/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ export const tuple = <T>(arr: T[]): Tuple<T>[] => arr.reduce((acc: Tuple<T>[], e
return acc;
}, []);

/** Flat array */
/** Flat array - unwraps one level of nested arrays */
export const flat = <T>(arr: (null | T | T[])[]): T[] =>
arr.reduce((acc: T[], el) => el ? acc.concat(el) : acc, []) as T[];

/** Wrap to array */
/** Wrap passed object to array */
export const wrap = <T>(arr: undefined | null | T | T[]): T[] => {
if (arr === undefined || arr === null) return [];
if (Array.isArray(arr)) return arr;
Expand All @@ -39,46 +39,3 @@ export function range(n: number, filler: (i: number) => any = identity): any[] {
while (i < n) arr[i] = filler(i++);
return arr;
}

/** */
export function intersection(a?: any): never;
export function intersection<T>(a: T[]): T[];
/** Create an array of unique values that presented in each of the passed arrays */
export function intersection<T>(...rest: T[][]): T[];
export function intersection<T>(a?: T[], b?: T[], ...rest: T[][]): T[] | undefined {
if (!a || !b) throw new Error('The method call should have at least 2 arguments');
if (rest.length) return intersection(a, intersection(b, ...rest));
return a.filter(Set.prototype.has, new Set(b));
}

export function union(): never;
export function union<T>(...rest: T[][]): T[];
/** Create an array with the unique values from each of the passed arays */
export function union<T>(...rest: T[][]): T[] {
if (!rest.length) throw new Error('The method call should have at least 2 arguments');
const set = new Set();
rest.forEach(item => item.forEach(i => set.add(i)));
const result: any[] = [];
set.forEach(value => result.push(value));
return result;
}

/** */
export function complement(a?: any): never;
/** Creates an array of unique values from the first array that are not present in the other arrays */
export function complement<T>(...rest: T[][]): T[];
export function complement<T>(a?: T[], b?: T[], ...rest: T[][]): T[] | undefined {
if (!a || !b) throw new Error('The method call should have at least 2 arguments');
if (rest.length > 1) return complement(a, complement(b, ...rest));
const setB = new Set(b);
return a.filter(element => !setB.has(element));
}


/** Check for elements from array B in array A */
export function fullIntersection<T>(a: T[], b: T[]): boolean {
if (a.length === 0 && b.length === 0) return true;
const {testedArr, arr} = a.length >= b.length ? {testedArr: a, arr: b} : {testedArr: b, arr: a};
const set = new Set(testedArr);
return !arr.filter((item: T) => !set.has(item)).length;
}
36 changes: 36 additions & 0 deletions src/modules/esl-utils/misc/set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** Create an array of unique values that presented in each of the passed arrays */
export function intersection<T>(...rest: T[][]): T[];
export function intersection<T>(a: T[], b: T[], ...rest: T[][]): T[] {
if (arguments.length < 2) return a ? a.slice() : [];
if (rest.length) return intersection(a, intersection(b, ...rest));
return a.filter(Set.prototype.has, new Set(b));
}

/** Create an array with unique values from each of the passed arrays */
export function union<T>(...rest: T[][]): T[] {
const set = new Set();
rest.forEach(item => item.forEach(i => set.add(i)));
const result: any[] = [];
set.forEach(value => result.push(value));
return result;
}

/** Creates an array of unique values from the first array that are not present in the other arrays */
export function complement<T>(...rest: T[][]): T[];
export function complement<T>(a: T[], b: T[], ...rest: T[][]): T[] | undefined {
if (!b) return a ? a.slice() : [];
if (rest.length > 1) return complement(a, complement(b, ...rest));
const setB = new Set(b);
return a.filter(element => !setB.has(element));
}

/**
* @returns if the passed arrays have a full intersection
* Expect uniq values in collections
*/
export function fullIntersection<T>(a: T[], b: T[]): boolean {
if (a.length === 0 && b.length === 0) return true;
const [larger, smaller] = a.length >= b.length ? [a, b] : [b, a];
const set = new Set(larger);
return !smaller.filter((item: T) => !set.has(item)).length;
}
44 changes: 1 addition & 43 deletions src/modules/esl-utils/misc/test/array.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {flat, range, tuple, uniq, wrap, intersection, union, complement, fullIntersection} from '../array';
import {flat, range, tuple, uniq, wrap} from '../array';

describe('misc/array helper tests', () => {
test('tuple', () => {
Expand Down Expand Up @@ -45,45 +45,3 @@ describe('misc/array helper tests', () => {
expect(range(9, (x) => x / 8)).toEqual([...Array(9).keys()].map((x) => x / 8))
});
});

test('intersection', () => {
const a = {a: 3};
expect(intersection([],[])).toEqual([]);
expect(intersection([1],[1])).toEqual([1]);
expect(intersection([1, 2, 3], [1, 2], [1, 2, 4])).toEqual([1, 2]);
expect(intersection([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([1, a]);
expect(intersection([null, 1, 2, 3, [6]], [4, 5])).toEqual([]);
expect(intersection([1, 2, 3, [6]], [4, 5, 1, 2], [1])).toEqual([1]);
expect(intersection([NaN],[NaN])).toEqual([NaN]);
});

test('union', () => {
const a = {a:3};
expect(union([], [])).toEqual([]);
expect(union([1], [1])).toEqual([1]);
expect(union([1, 2], [1, 2], [1, 2])).toEqual([1, 2,]);
expect(union([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([1, [2, 3], a, [2, 3]]);
expect(union([1, 2, 3, null, [6]], [4, 5], [1, 2, 3, null, [6]], [4, 5])).toEqual([1, 2, 3, null, [6], 4, 5, [6]]);
expect(union([NaN],[NaN])).toEqual([NaN]);
});

test('complement', () => {
const a = {a: 3};
expect(complement([],[])).toEqual([]);
expect(complement([1],[1])).toEqual([]);
expect(complement([1, 2, 3], [1, 2], [1, 2, 5])).toEqual([3]);
expect(complement([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([[2, 3]]);
expect(complement([null, 1, 2, 3, [6]], [4, 5])).toEqual([null, 1, 2, 3,[6]]);
expect(complement([NaN],[NaN])).toEqual([]);
});

test('fullIntersection', () => {
const a = {a: 3};
expect(fullIntersection([],[])).toEqual(true);
expect(fullIntersection([1],[1])).toEqual(true);
expect(fullIntersection([1, 2, 3], [1, 2])).toEqual(true);
expect(fullIntersection([1, [2, 3], a], [a, 1, [2, 3]])).toEqual(false);
expect(fullIntersection([null, 1, 2, 3, [6]], [4, 5])).toEqual(false);
expect(fullIntersection([null, 1, 2, 3, [6]], [4, 5, null, 1, 2, 3, [6]])).toEqual(false);
});

50 changes: 50 additions & 0 deletions src/modules/esl-utils/misc/test/set.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {complement, fullIntersection, intersection, union} from '../set';

describe('set', () => {
test('intersection', () => {
const a = {a: 3};
expect(intersection()).toEqual([]);
expect(intersection([1])).toEqual([1]);
expect(intersection([],[])).toEqual([]);
expect(intersection([1],[1])).toEqual([1]);
expect(intersection([1, 2, 3], [1, 2], [1, 2, 4])).toEqual([1, 2]);
expect(intersection([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([1, a]);
expect(intersection([null, 1, 2, 3, [6]], [4, 5])).toEqual([]);
expect(intersection([1, 2, 3, [6]], [4, 5, 1, 2], [1])).toEqual([1]);
expect(intersection([NaN],[NaN])).toEqual([NaN]);
});

test('union', () => {
const a = {a:3};
expect(union()).toEqual([]);
expect(union([1])).toEqual([1]);
expect(union([], [])).toEqual([]);
expect(union([1], [1])).toEqual([1]);
expect(union([1, 2], [1, 2], [1, 2])).toEqual([1, 2,]);
expect(union([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([1, [2, 3], a, [2, 3]]);
expect(union([1, 2, 3, null, [6]], [4, 5], [1, 2, 3, null, [6]], [4, 5])).toEqual([1, 2, 3, null, [6], 4, 5, [6]]);
expect(union([NaN],[NaN])).toEqual([NaN]);
});

test('complement', () => {
const a = {a: 3};
expect(complement()).toEqual([]);
expect(complement([1])).toEqual([1]);
expect(complement([],[])).toEqual([]);
expect(complement([1],[1])).toEqual([]);
expect(complement([1, 2, 3], [1, 2], [1, 2, 5])).toEqual([3]);
expect(complement([1, [2, 3], a], [a, 1, [2, 3]])).toEqual([[2, 3]]);
expect(complement([null, 1, 2, 3, [6]], [4, 5])).toEqual([null, 1, 2, 3,[6]]);
expect(complement([NaN],[NaN])).toEqual([]);
});

test('fullIntersection', () => {
const a = {a: 3};
expect(fullIntersection([],[])).toEqual(true);
expect(fullIntersection([1],[1])).toEqual(true);
expect(fullIntersection([1, 2, 3], [1, 2])).toEqual(true);
expect(fullIntersection([1, [2, 3], a], [a, 1, [2, 3]])).toEqual(false);
expect(fullIntersection([null, 1, 2, 3, [6]], [4, 5])).toEqual(false);
expect(fullIntersection([null, 1, 2, 3, [6]], [4, 5, null, 1, 2, 3, [6]])).toEqual(false);
});
})

0 comments on commit b8828ab

Please sign in to comment.