Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Reusable Snippets|Practical utility code for everyday use — custom-built and ready to share

unionBy

Returns an array of distinct elements from both arrays using a key selector. If elements from both arrays share the same key, only the first occurrence is kept.

TypeScript
Copied!
1/**
2 * Returns an array of distinct elements from both arrays using a key selector.
3 * If elements from both arrays share the same key, only the first occurrence is kept.
4 *
5 * @param a - First array.
6 * @param b - Second array.
7 * @param keyFn - Function to extract a comparable key from each element.
8 * @returns A new array with unique elements by key.
9 */
10export function unionBy<T>(
11  a: T[],
12  b: T[],
13  keyFn: (item: T) => string | number
14): T[] {
15  const seen = new Set<string | number>();
16  const result: T[] = [];
17
18  for (const item of [...a, ...b]) {
19    const key = keyFn(item);
20    if (!seen.has(key)) {
21      seen.add(key);
22      result.push(item);
23    }
24  }
25
26  return result;
27}
  • Custom key-based uniqueness

    Allows merging arrays while ensuring uniqueness based on a derived key (e.g. id, slug, name), not just strict equality. This is more flexible than the standard Set-based union.

  • Order of first occurrence preserved

    Keeps the first occurrence of each unique key from the merged input arrays, which is often desirable in UI lists, priority-based logic, or user-defined preferences.

  • Efficient one-pass filtering

    Performs all operations in a single loop with O(n) complexity thanks to the Set for tracking seen keys.

  • Pure and immutable

    Does not modify the input arrays and produces a new result array.

  • Works with both primitives and objects

    Ideal for de-duplicating object arrays where equality must be derived from a specific property.

Tests | Examples

TypeScript
Copied!
1test('unionBy - with objects and id key', () => {
2  const arr1 = [{ id: 1 }, { id: 2 }];
3  const arr2 = [{ id: 2 }, { id: 3 }];
4  expect(unionBy(arr1, arr2, item => item.id)).toEqual([
5    { id: 1 },
6    { id: 2 },
7    { id: 3 },
8  ]);
9});
10
11test('unionBy - using length as key', () => {
12  const arr1 = ['a', 'bb'];
13  const arr2 = ['ccc', 'dd'];
14  expect(unionBy(arr1, arr2, str => str.length)).toEqual(['a', 'bb', 'ccc']);
15});
16
17test('unionBy - one array empty', () => {
18  expect(unionBy([], [{ id: 1 }], item => item.id)).toEqual([{ id: 1 }]);
19});
20
21test('unionBy - both arrays empty', () => {
22  expect(unionBy([], [], item => item)).toEqual([]);
23});

Common Use Cases

  • Merging API results or paginated data

    Combine responses from multiple pages or endpoints while eliminating duplicates based on a consistent identifier.

  • Deduplicating items in UI components

    Useful when rendering a merged feed of cards, suggestions, or search results with potential overlap.

  • Data normalization

    Aggregate data from different sources and ensure each entity appears only once by key.

  • Building unique dropdowns or filters

    Construct a deduplicated list of options based on object keys.

Codebase: Utilities -> Arrays -> unionBy | Yevhen Klymentiev