Lodash _.unionWith() method
What you’ll learn
- How
_.unionWith(...arrays, comparator)unions arrays using pairwise equality you define. - When to plug in
_.isEqualversus a lightweight field comparison. - How this differs from _.union() (SameValueZero) and _.unionBy() (iteratee keys).
- Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Skim _.differenceWith() for the same comparator contract applied to subtraction instead of merging.
- You can write pure binary predicates without hidden mutable state.
- You can open Try-it labs or run snippets locally.
Overview
_.unionWith is the escape hatch when equality is contextual—timestamp tolerances, deep structural matches, or composite business keys too expressive for a simple iteratee.
Custom equality
Any comparator Lodash accepts elsewhere works here—no forced projections.
Deterministic winners
Earlier arguments keep their rows—plan merges when freshness matters.
Immutable sources
Inputs remain pristine for retries or alternate comparators.
Syntax
_.unionWith(...arrays, comparator) - arrays: collections merged sequentially before uniqueness runs.
- comparator: invoked as
(arrVal, othVal); truthy means treat the pair as duplicates. - Returns: new array containing first occurrences under your comparator.
Match rows by shared sku
Different object shapes still collide when the comparator narrows on a stable identifier.
import unionWith from "lodash/unionWith";
unionWith(
[{ sku: "A1", qty: 5 }],
[{ sku: "B2" }, { sku: "A1", note: "duplicate" }],
(a, b) => a.sku === b.sku
);
// → [{ sku: "A1", qty: 5 }, { sku: "B2" }] Deep structure with _.isEqual
Nested literals that fail reference equality still collapse when Lodash deems them deeply equivalent.
import unionWith from "lodash/unionWith";
import isEqual from "lodash/isEqual";
unionWith(
[{ id: 7, meta: { tier: "gold" } }],
[{ id: 9 }, { id: 7, meta: { tier: "gold" } }],
isEqual
);
// → [{ id: 7, meta: { tier: "gold" } }, { id: 9 }] Several arrays, one comparator
Variadic unions behave like union; only the terminal comparator differs.
import unionWith from "lodash/unionWith";
unionWith([{ x: 1 }], [{ x: 2 }], [{ x: 1, flag: true }], (a, b) => a.x === b.x);
// → [{ x: 1 }, { x: 2 }] 📋 _.unionWith vs union, unionBy, uniqWith
| API | Equality signal | Best when |
|---|---|---|
_.unionWith(...arrays, comparator) | Binary predicate | Custom rules spanning multiple inputs |
_.union(...arrays) | SameValueZero on elements | Primitives or reference-stable rows |
_.unionBy(...arrays, iteratee) | Projected keys | Single-field uniqueness suffices |
_.uniqWith(array, comparator) | Binary predicate | Only one array needs deduping |
Pitfalls to avoid
Comparator cost
Rich predicates can dominate runtime on large merges—profile before shipping hot paths.
Asymmetry surprises
Odd comparators that are not symmetric cause confusing merges; keep predicates predictable.
Stale winners
Remember first occurrence wins—swap argument order or sort upstream when newer payloads must replace older twins.
❓ FAQ
Summary
- Purpose:
_.unionWith(...arrays, comparator)merges arrays while deduping via your comparator. - Contrast: drop down to unionBy when a simple iteratee suffices.
- Next: Lodash _.uniq(), _.unionBy() (previous), or the array methods hub.
The comparator mirrors _.differenceWith(): return a truthy value when two candidates should count as the same logical element—even if their references differ.
6 people found this page helpful
