Lodash difference vs differenceBy Explained

The primary difference between the _.difference and _.differenceBy methods in Lodash lies in how they evaluate elements for comparison. While _.difference compares array values directly using standard equality, _.differenceBy allows you to pass an iteratee function or property shorthand to transform or inspect elements before the comparison takes place. This makes _.difference ideal for primitive arrays and _.differenceBy the go-to choice for complex data structures, such as arrays of objects.

Understanding _.difference

The _.difference method takes a base array and one or more arrays of values to exclude. It returns a new array containing only the elements from the base array that are not present in the other arrays.

Under the hood, _.difference uses the SameValueZero algorithm for equality comparisons, similar to ===. Because it compares values directly by identity, it works effectively with primitive data types such as strings, numbers, and booleans.

const _ = require('lodash');

const numbers = [2, 1, 5, 3];
const toExclude = [2, 3];

const result = _.difference(numbers, toExclude);
// Output: [1, 5]

However, _.difference fails when dealing with non-primitive types like objects, unless both arrays reference the exact same object instances in memory:

const usersA = [{ id: 1 }, { id: 2 }];
const usersB = [{ id: 1 }];

// Fails because the objects have different memory references
const result = _.difference(usersA, usersB);
// Output: [{ id: 1 }, { id: 2 }]

Understanding _.differenceBy

The _.differenceBy method accepts the same arguments as _.difference, but adds an iteratee as its final argument. The iteratee is invoked for each element in all provided arrays to generate the criterion by which values are compared.

The iteratee can be:

Example with Property Names

When working with arrays of objects, you can supply a property name to filter out items sharing the same property value:

const usersA = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
const usersB = [{ id: 1, name: 'Alice' }];

const result = _.differenceBy(usersA, usersB, 'id');
// Output: [{ id: 2, name: 'Bob' }]

Example with a Custom Function

You can also supply a custom function to transform values prior to comparison, such as rounding numbers:

const decimalsA = [2.1, 1.2, 3.7];
const decimalsB = [2.3, 3.4];

const result = _.differenceBy(decimalsA, decimalsB, Math.floor);
// Output: [1.2]

In this scenario, 2.1 and 2.3 both floor to 2, and 3.7 and 3.4 both floor to 3, leaving only 1.2.

Key Differences Summary

Feature _.difference _.differenceBy
Comparison Strategy Direct comparison via SameValueZero. Compares the results of an applied iteratee.
Iteratee Support No iteratee support. Accepts a function, property key, or path.
Best Used For Flat arrays of primitive values. Arrays of objects or transformed comparisons.
Performance Slightly faster due to the absence of callback execution. Carries minor overhead from invoking the iteratee.