Using Lodash differenceWith for Custom Array Comparisons
The Lodash _.differenceWith method allows developers to
compare arrays using a custom comparator function instead of relying on
default shallow equality. This makes it an essential tool when filtering
complex datasets, such as arrays of objects, where values need to be
evaluated based on specific properties or deep structural equality. This
guide explains how _.differenceWith works and provides
practical code examples demonstrating how to implement custom comparison
logic in your JavaScript applications.
Syntax and Parameters
The syntax for _.differenceWith is:
_.differenceWith(array, [values], [comparator])array: The primary array from which you want to exclude values.[values]: One or more arrays containing the values to exclude.[comparator]: A function invoked to compare elements fromarrayagainst elements invalues. It receives two arguments(arrVal, othVal)and should returntrueif the values are considered equal, orfalseotherwise.
Why Use
_.differenceWith Instead of _.difference?
Standard array difference methods like _.difference use
the SameValueZero algorithm (similar to ===), which
compares object references rather than their internal properties. When
working with arrays of objects, _.difference fails to
detect identical objects with different memory references:
const listA = [{ id: 1, name: 'Alice' }];
const listB = [{ id: 1, name: 'Alice' }];
// Returns [{ id: 1, name: 'Alice' }] because the references differ
_.difference(listA, listB); _.differenceWith solves this issue by letting you define
the exact condition that determines whether two elements match.
Comparing Objects by a Specific Property
In many scenarios, you only need to check if a specific key—such as an ID—matches between two sets of objects.
const _ = require('lodash');
const currentUsers = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Charlie' }
];
const inactiveUsers = [
{ id: 102, name: 'Bob' }
];
// Keep only users whose IDs do not appear in inactiveUsers
const activeUsers = _.differenceWith(
currentUsers,
inactiveUsers,
(userA, userB) => userA.id === userB.id
);
console.log(activeUsers);
// Output: [ { id: 101, name: 'Alice' }, { id: 103, name: 'Charlie' } ]Deep Object Comparison
with _.isEqual
If you need to filter out objects that are identical across all keys
and nested properties, you can pass Lodash’s _.isEqual
method directly as the comparator function:
const _ = require('lodash');
const baseInventory = [
{ sku: 'A1', stock: 10, details: { warehouse: 'East' } },
{ sku: 'B2', stock: 5, details: { warehouse: 'West' } },
{ sku: 'C3', stock: 0, details: { warehouse: 'East' } }
];
const processedInventory = [
{ sku: 'A1', stock: 10, details: { warehouse: 'East' } }
];
const remainingInventory = _.differenceWith(
baseInventory,
processedInventory,
_.isEqual
);
console.log(remainingInventory);
// Output:
// [
// { sku: 'B2', stock: 5, details: { warehouse: 'West' } },
// { sku: 'C3', stock: 0, details: { warehouse: 'East' } }
// ]Using Multiple Exclusion Arrays
_.differenceWith accepts multiple arrays of values to
filter out. The comparator will evaluate items against all subsequent
arrays:
const numbers = [1.2, 2.4, 3.7, 4.1];
const excludeList1 = [1.8];
const excludeList2 = [3.2];
// Exclude numbers with the same rounded value
const filtered = _.differenceWith(
numbers,
excludeList1,
excludeList2,
(a, b) => Math.floor(a) === Math.floor(b)
);
console.log(filtered);
// Output: [ 2.4, 4.1 ]Performance Considerations
Because _.differenceWith executes the comparator
function by iterating through elements in the exclusion arrays for each
item in the base array, its time complexity is \(O(n \times m)\) where \(n\) is the length of the source array and
\(m\) is the total length of the
comparison arrays. For very large datasets with simple unique keys,
mapping to a Set of primitives may provide better
performance than running nested iterations.