Lodash sortedUniqBy with Different Object Shapes

Lodash's _.sortedUniqBy processes sorted arrays by running an iteratee function over each element and discarding adjacent duplicates based on the returned values. When dealing with objects of differing shapes where the iteratee yields the exact same value, the method strictly adheres to a "first seen, first kept" policy. It completely ignores structural, type, or property differences outside of the iteratee's output, preserving only the first occurrence among consecutive duplicates and omitting the rest.

The Comparison Mechanism

_.sortedUniqBy is optimized specifically for arrays that are already sorted according to the criteria defined by the iteratee. Unlike _.uniqBy, which typically checks every item against a set of all previously seen values, _.sortedUniqBy only compares the iteratee result of the current item to the iteratee result of the immediately preceding retained item.

The algorithm uses the SameValueZero comparison on the values produced by the iteratee:

  1. The iteratee function executes on the first element, and this element is automatically added to the result array.
  2. The iteratee executes on the next element.
  3. If the computed value matches the computed value of the previously kept element, the current element is discarded.
  4. If the computed value differs, the current element is retained, and its computed value becomes the new baseline for subsequent comparisons.

Processing Differing Object Shapes

JavaScript objects can have entirely different schemas, keys, or prototype chains. However, _.sortedUniqBy is structurally agnostic. It does not perform a deep comparison, nor does it attempt to merge properties across differing shapes.

Consider an example where the iteratee extracts an id property:

const items = [
  { id: 10, name: 'Alpha', active: true },
  { id: 10, title: 'Beta', metadata: { role: 'admin' } },
  { id: 20, type: 'Gamma' }
];

const result = _.sortedUniqBy(items, 'id');

The resulting array will be:

[
  { id: 10, name: 'Alpha', active: true },
  { id: 20, type: 'Gamma' }
]

Even though the second object contains keys (title, metadata) that the first object lacks, _.sortedUniqBy only evaluates the property 'id'. Because both return 10, the second object is deemed a duplicate and discarded.

Critical Considerations