본문으로 건너뛰기

differenceWith

Returns elements from the source array that are not present in the exclude array, using a custom comparison function to determine element equality. Creates a new array containing elements from the source array that do not have matching elements in the exclude array based on a custom equality comparison. This is useful when you need complex comparison logic that cannot be expressed with simple value transformation.

Signature

const differenceWith: <Type1, Type2>(source: Type1[], exclude: Type2[], isEqual: (source: Type1, exclude: Type2) => boolean) => Type1[]

Parameters

NameTypeDescription
source-Source array that serves as the base for comparison
exclude-Array containing elements to exclude from the result
isEqual-Comparison function to determine if two elements are equal

Returns

Array of elements that exist only in the source array

Examples

Compare objects with custom logic

import { differenceWith } from '@winglet/common-utils';

const products = [
{ id: 1, name: 'iPhone', price: 999 },
{ id: 2, name: 'iPad', price: 799 },
{ id: 3, name: 'MacBook', price: 1299 }
];

const discontinued = [
{ id: 1, name: 'iPhone', price: 899 }, // Different price, same product
{ id: 4, name: 'iPod', price: 199 }
];

// Compare by name only, ignoring price differences
const result = differenceWith(
products,
discontinued,
(a, b) => a.name === b.name
);
console.log(result); // [{ id: 2, name: 'iPad', ... }, { id: 3, name: 'MacBook', ... }]

Case-insensitive string comparison

const originalList = ['Apple', 'Banana', 'Orange', 'Grape'];
const toRemove = ['apple', 'BANANA'];

const result = differenceWith(
originalList,
toRemove,
(a, b) => a.toLowerCase() === b.toLowerCase()
);
console.log(result); // ['Orange', 'Grape']

Complex object comparison with multiple criteria

interface Person {
firstName: string;
lastName: string;
age: number;
email: string;
}

const allPeople: Person[] = [
{ firstName: 'John', lastName: 'Doe', age: 30, email: 'john@example.com' },
{ firstName: 'Jane', lastName: 'Doe', age: 28, email: 'jane@example.com' },
{ firstName: 'Bob', lastName: 'Smith', age: 35, email: 'bob@example.com' }
];

const duplicates: Person[] = [
{ firstName: 'John', lastName: 'Doe', age: 31, email: 'john.doe@example.com' } // Different age and email
];

// Compare by first and last name only
const result = differenceWith(
allPeople,
duplicates,
(a, b) => a.firstName === b.firstName && a.lastName === b.lastName
);
console.log(result); // [{ firstName: 'Jane', ... }, { firstName: 'Bob', ... }]

Approximate numeric comparison

const measurements = [1.0, 2.5, 3.7, 4.9, 5.1];
const targets = [1.1, 5.0]; // Close approximations

const result = differenceWith(
measurements,
targets,
(a, b) => Math.abs(a - b) < 0.2 // Within 0.2 tolerance
);
console.log(result); // [2.5, 3.7, 4.9]

Array comparison

const coordinates = [[1, 2], [3, 4], [5, 6], [7, 8]];
const toExclude = [[1, 2], [5, 6]];

const result = differenceWith(
coordinates,
toExclude,
(a, b) => a[0] === b[0] && a[1] === b[1]
);
console.log(result); // [[3, 4], [7, 8]]

Date comparison with custom logic

const events = [
{ name: 'Meeting', date: new Date('2024-01-15') },
{ name: 'Conference', date: new Date('2024-02-20') },
{ name: 'Workshop', date: new Date('2024-03-10') }
];

const conflicts = [
{ name: 'Other Meeting', date: new Date('2024-01-15') }
];

// Compare by date only, ignore event names
const result = differenceWith(
events,
conflicts,
(a, b) => a.date.getTime() === b.date.getTime()
);
console.log(result); // [{ name: 'Conference', ... }, { name: 'Workshop', ... }]

Playground

import { differenceWith } from '@winglet/common-utils';

const products = [
{ id: 1, name: 'iPhone', price: 999 },
{ id: 2, name: 'iPad', price: 799 },
{ id: 3, name: 'MacBook', price: 1299 }
];

const discontinued = [
{ id: 1, name: 'iPhone', price: 899 }, // Different price, same product
{ id: 4, name: 'iPod', price: 199 }
];

// Compare by name only, ignoring price differences
const result = differenceWith(
products,
discontinued,
(a, b) => a.name === b.name
);
console.log(result); // [{ id: 2, name: 'iPad', ... }, { id: 3, name: 'MacBook', ... }]

Notes

Performance: Uses nested loops with O(n×m) time complexity where n is source length and m is exclude length. Consider using differenceBy with a hash function for large arrays.

Comparison Function: The isEqual function should be pure and symmetric. It receives elements from source as first parameter and exclude as second parameter.

Type Safety: Supports different types for source and exclude arrays as long as the comparison function can handle both types.

Order Preservation: Maintains the original order of elements from the source array in the result array.