Skip to content

Commit

Permalink
feat: remove array duplicates by value & reference
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed May 19, 2023
1 parent 2a01a6a commit b55dcfc
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 56 deletions.
22 changes: 20 additions & 2 deletions src/utils/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,32 @@
* view the LICENSE file that was distributed with this source code.
*/

import { isEqual } from './check';

export function distinctArray(arr: any[]) {
const copy = [...arr];

for (let i = 0; i < copy.length; i++) {
for (let j = copy.length - 1; j > i; j--) {
if (isEqual(copy[i], copy[j])) {
copy.splice(j, 1);
}
}
}

return copy;
}

export function mergeArrays(
first: any[],
second: any[],
arrayDistinct: boolean,
) {
const merged = first.concat(second);

if (arrayDistinct) {
return [...new Set(first.concat(second))];
return distinctArray(merged);
}

return first.concat(second);
return merged;
}
58 changes: 33 additions & 25 deletions src/utils/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
* view the LICENSE file that was distributed with this source code.
*/

import { hasOwnProperty } from './has-own-property';

export function isObject(item: unknown) : item is Record<string, any> {
return (
!!item &&
Expand All @@ -15,29 +13,6 @@ export function isObject(item: unknown) : item is Record<string, any> {
);
}

export function isObjectDeeperThan(value: unknown, depth: number) {
if (depth <= 0) {
return isObject(value);
}

if (!isObject(value)) {
return false;
}

const nextDepth = depth - 1;
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) {
if (
hasOwnProperty(value, keys[i]) &&
isObjectDeeperThan(value[keys[i]], nextDepth)
) {
return true;
}
}

return false;
}

export function isSafeObject(object: Record<string, any>) : boolean {
try {
JSON.stringify(object);
Expand All @@ -52,3 +27,36 @@ export function isSafeKey(key: string) : boolean {
key !== 'prototype' &&
key !== 'constructor';
}

export function isEqual(x: any, y: any): boolean {
if (Object.is(x, y)) return true;

if (x instanceof Date && y instanceof Date) {
return x.getTime() === y.getTime();
}

if (x instanceof RegExp && y instanceof RegExp) {
return x.toString() === y.toString();
}

if (!isObject(x) || !isObject(y)) {
return false;
}

const keysX = Reflect.ownKeys(x) as string[];
const keysY = Reflect.ownKeys(y) as string[];
if (keysX.length !== keysY.length) return false;

for (let i = 0; i < keysX.length; i++) {
const key = keysX[i];
if (!Reflect.has(y, key)) {
return false;
}

if (!isEqual(x[key], y[key])) {
return false;
}
}

return true;
}
36 changes: 36 additions & 0 deletions test/unit/utils/array.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import {distinctArray, mergeArrays} from "../../../src";

describe('src/utils/array', function () {
it('should distinct array', () => {
let arr: any[] = [0, 1, 2, 3];

expect(distinctArray(arr)).toEqual(arr);

arr = [0, 1, 2, 0, 0];
expect(distinctArray(arr)).toEqual([0, 1, 2]);

arr = [{foo: 'bar'}, {foo: 'bar'}]

expect(distinctArray(arr)).toEqual([{ foo: 'bar' }]);

let circ : any = {foo: 'bar'};
circ.bar = circ;

arr = [{foo: { bar: 'baz'}}, circ];
expect(distinctArray(arr)).toEqual(arr);
})

it('should merge arrays', () => {
let x = ['foo', 'bar', 'baz'];
let y = ['baz', 'moo', 'bar', 'mal'];

expect(mergeArrays(x, y, true)).toEqual(['foo', 'bar', 'baz', 'moo', 'mal']);
})
});
31 changes: 2 additions & 29 deletions test/unit/utils.spec.ts → test/unit/utils/cut.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Copyright (c) 2022.
* Copyright (c) 2022-2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import {cutObject, isObjectDeeperThan} from "../../src";
import { cutObject } from "../../../src";



Expand Down Expand Up @@ -38,31 +38,4 @@ describe('src/utils/*.ts', () => {
depth = cutObject(nested, 3);
expect(depth).toEqual({ a: { a: { a: { b: 1 } } } } );
});

it('should determine depth correct', () => {
// {} = 0
// { key: {} } = 1

let ob = {};

expect(isObjectDeeperThan(ob, 0)).toEqual(true);
expect(isObjectDeeperThan(ob, 1)).toEqual(false);

// ---------------------------------------------

const nested = {
a: {
a: {

},
foo: 'bar'
}
}

expect(isObjectDeeperThan(nested, 0)).toEqual(true);
expect(isObjectDeeperThan(nested, 1)).toEqual(true);
expect(isObjectDeeperThan(nested, 2)).toEqual(true);
expect(isObjectDeeperThan(nested, 3)).toEqual(false);
expect(isObjectDeeperThan(nested, 4)).toEqual(false);
})
})
1 change: 1 addition & 0 deletions tsconfig.eslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"commitlint.config.js",
"release.config.js",
"rollup.config.mjs"
Expand Down

0 comments on commit b55dcfc

Please sign in to comment.