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:

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.