Lodash xorBy String Comparison Across Locales
The _.xorBy method in the Lodash JavaScript library
creates an array of unique values representing the symmetric difference
between given arrays, using an iteratee function to extract the
comparison criteria. However, Lodash does not provide built-in
internationalization or locale-sensitive string evaluation. To process
string comparisons across different language locales using
_.xorBy, developers must supply a custom iteratee that
leverages native JavaScript internationalization tools, such as
String.prototype.normalize() or Intl.Collator,
to standardize characters before Lodash evaluates their uniqueness.
Native Comparison Behavior in Lodash
Internally, Lodash’s comparison mechanisms (including those powering
_.xorBy) rely on the SameValueZero algorithm.
When comparing primitive strings, this algorithm matches character
sequences strictly by their binary UTF-16 code units.
Because SameValueZero performs binary evaluation:
- Diacritics and accented characters (e.g., "e" versus "é") are treated as distinct values.
- Equivalent Unicode representations (such as a precomposed character versus a combining character sequence) evaluate as unequal unless normalized.
- Case distinctions and language-specific collation rules (such as the Turkish dotted and dotless "i") are ignored unless explicitly handled before evaluation.
How _.xorBy Applies the Iteratee
_.xorBy accepts an iteratee as its final argument:
_.xorBy([arrays], [iteratee=_.identity])During execution, _.xorBy runs each element through this
iteratee function to generate a comparison criterion. The returned value
from the iteratee is what Lodash checks against its internal hash maps
and sets using SameValueZero. The original values
corresponding to the unique criteria are preserved in the final output
array.
Implementing Locale-Aware Comparison
To make _.xorBy locale-aware, you must pass a custom
iteratee function that normalizes string inputs according to the rules
of the desired language locale.
1. Unicode Normalization and Case Folding
For general cross-language handling where accents or distinct forms
of identical characters should match, use
String.prototype.normalize() alongside
String.prototype.toLocaleLowerCase():
const _ = require('lodash');
const listA = ['resume', 'café'];
const listB = ['résumé', 'CAFE'];
const result = _.xorBy(listA, listB, (item) =>
item
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLocaleLowerCase('en')
);In this implementation, the iteratee strips accents and converts
casing based on the specified locale, allowing _.xorBy to
recognize "café" and "CAFE" as equivalent.
2. Handling Complex Locales with Sort Keys
When comparing strings based on formal linguistic equivalence where simple lowercasing is insufficient (such as distinguishing or equating specific digraphs or accents depending on the language), you can generate collation keys or normalized canonical tokens:
const _ = require('lodash');
const group1 = ['ä'];
const group2 = ['ae'];
// German phonebook collation treats 'ä' similarly to 'ae'
const collator = new Intl.Collator('de-DE-u-co-phonebk', { sensitivity: 'base' });
function getCollationKey(str) {
// Normalize base characters for locale-specific comparison
return str.normalize('NFC').toLocaleLowerCase('de-DE');
}
const uniqueValues = _.xorBy(group1, group2, getCollationKey);Lodash delegates the generation of comparison criteria entirely to
the iteratee. By ensuring the iteratee transforms localized strings into
uniform canonical representations, _.xorBy effectively
executes locale-accurate symmetric differences across diverse language
datasets.