Lodash _.xorWith() method
What you’ll learn
- How
_.xorWith(...arrays, comparator)applies symmetric difference using your pairwise predicate. - Why comparators follow the same
(arrVal, othVal)shape as _.unionWith(). - When _.xorBy() or plain _.xor() stays simpler than custom compares.
- Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Read _.xorBy() first—if a single iteratee captures collisions, you rarely need the heavier comparator path.
- You can implement symmetric compares without hidden mutable state.
- You can open Try-it labs or run snippets locally.
Overview
_.xorWith covers XOR-style diffs where equality is fuzzy—deep payloads, composite keys, or domain-specific matching rules that would awkwardly squeeze into one iteratee.
Binary compares
You decide when two rows cancel during symmetric folding.
Shared XOR semantics
Conceptually still symmetric difference—matches disappear instead of merging.
Immutable inputs
Sources remain intact for alternate comparisons or auditing.
Syntax
_.xorWith(...arrays, comparator) - arrays: two or more collections participating in symmetric difference.
- comparator: invoked as
(arrVal, othVal); truthy means treat the pair as duplicates for cancellation. - Returns: new array of exclusive survivors under your comparator.
Rows matched by sku
Overlap on sku cancels both representatives—only exclusive SKUs remain.
import xorWith from "lodash/xorWith";
xorWith(
[{ sku: "A1" }, { sku: "B2" }],
[{ sku: "B2" }, { sku: "C3" }],
(a, b) => a.sku === b.sku
);
// → [{ sku: "A1" }, { sku: "C3" }] Deep equality with _.isEqual
Distinct references still cancel when Lodash deems structures deeply equivalent.
import xorWith from "lodash/xorWith";
import isEqual from "lodash/isEqual";
xorWith(
[{ id: 1, meta: { z: 1 } }],
[{ id: 2 }, { id: 1, meta: { z: 1 } }],
isEqual
);
// → [{ id: 2 }] Case-insensitive strings
Primitives compare fine—fold casing inside the comparator when lexeme identity should ignore case.
import xorWith from "lodash/xorWith";
xorWith(
["a", "B"],
["A", "c"],
(x, y) => typeof x === "string" && typeof y === "string" && x.toLowerCase() === y.toLowerCase()
);
// → ["B", "c"] 📋 _.xorWith vs xor, xorBy, differenceWith
| API | Equality signal | Use case |
|---|---|---|
_.xorWith(...arrays, comparator) | Binary predicate | Symmetric difference with custom pairwise logic |
_.xor(...arrays) | SameValueZero | Primitives or reference-stable rows |
_.xorBy(...arrays, iteratee) | Projected keys | Single-field collisions |
_.differenceWith(array, ...values, comparator) | Binary predicate | Directed subtraction from first array only |
Pitfalls to avoid
Comparator cost
Deep compares magnify work on large arrays—measure hot paths.
Asymmetric predicates
Odd comparators that are not symmetric confuse XOR outcomes—keep rules predictable.
❓ FAQ
Summary
- Purpose:
_.xorWith(...arrays, comparator)symmetric-differences arrays using your comparator for duplicate detection. - Contrast: prefer xorBy when a lone iteratee expresses collisions cleanly.
- Next: Lodash _.zip(), _.xorBy() (previous), or the array methods hub.
Like _.unionWith(), the comparator answers “should these two slots cancel?”—truthy means treat them as duplicates for XOR folding.
6 people found this page helpful
