Skip to content
VersionSize

alternate

The alternate utility toggles an item's presence in an array. If the item exists (based on a value or a custom selector), it is removed. If it doesn't exist, it is added to the array using a specified strategy.

Implementation

View Source Code
ts
import type { Primitive } from '../types';

/**
 * Either adds or removes an item from an array, based on whether it already exists in the array.
 *
 * @example
 * ```ts
 * alternate([1, 2, 3], 4) // [1, 2, 3, 4]
 * alternate([1, 2, 3], 2) // [1, 3]
 *
 * alternate(
 *   [{ id: 1 }, { id: 2 }],
 *   { id: 3 },
 *   (obj) => obj.id,
 *   { strategy: 'prepend' }
 * ) // [{ id: 3 }, { id: 1 }, { id: 2 }]
 * ```
 *
 * @param array - The array to modify.
 * @param item - The item to add or remove.
 * @param selector - A function to determine the uniqueness of the item.
 * @param [options] - Options for the alternate operation.
 * @param [options.strategy] - The strategy to use when adding the item ('prepend' or 'append').
 *
 * @returns A new array with the item added or removed.
 */
export function alternate<T>(
  array: T[],
  item: T,
  selector?: (item: T) => Primitive,
  options: { strategy?: 'prepend' | 'append' } = {},
): T[] {
  const { strategy = 'append' } = options;
  const compareFn = selector ? (el: T) => selector(el) === selector(item) : (el: T) => el === item;

  const index = array.findIndex(compareFn);

  if (index !== -1) {
    return [...array.slice(0, index), ...array.slice(index + 1)];
  }

  return strategy === 'prepend' ? [item, ...array] : [...array, item];
}

alternate.fp = true;

Features

  • Isomorphic: Works in both Browser and Node.js.
  • Smart Toggling: Automatically handles addition and removal logic.
  • Custom Uniqueness: Support for complex objects via a selector function.
  • Flexible Positioning: Control where new items are added (prepend or append).

API

ts
function alternate<T>(
  array: T[],
  item: T,
  selector?: (item: T) => Primitive,
  options?: { strategy?: 'prepend' | 'append' },
): T[];

Parameters

  • array: The array to modify.
  • item: The item to toggle.
  • selector: Optional. A function that returns a primitive value used to determine uniqueness (defaults to direct comparison).
  • options: Optional configuration:
    • strategy: Where to add the item if it's missing ('prepend' or 'append', defaults to 'append').

Returns

  • A new array with the item either added or removed.

Examples

Toggling Primitives

ts
import { alternate } from '@vielzeug/toolkit';

const numbers = [1, 2, 3];

// Add 4
alternate(numbers, 4); // [1, 2, 3, 4]

// Remove 2
alternate(numbers, 2); // [1, 3]

Toggling Objects with a Selector

ts
import { alternate } from '@vielzeug/toolkit';

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
];
const newUser = { id: 3, name: 'Charlie' };
const existingUser = { id: 1, name: 'Alice Smith' };

// Toggle based on ID
const result1 = alternate(users, newUser, (u) => u.id);
// [{ id: 1, ... }, { id: 2, ... }, { id: 3, ... }]

const result2 = alternate(users, existingUser, (u) => u.id);
// [{ id: 2, name: 'Bob' }]

Using a Custom Strategy

ts
import { alternate } from '@vielzeug/toolkit';

const list = ['B', 'C'];

// Add 'A' to the beginning
alternate(list, 'A', undefined, { strategy: 'prepend' }); // ['A', 'B', 'C']

Implementation Notes

  • Returns a new array; the original array is never mutated.
  • When removing, all instances matching the item (or selector result) are removed.
  • Throws TypeError if the first argument is not an array.

See Also

  • filter: Manually remove items from an array.
  • uniq: Ensure all elements in an array are unique.
  • aggregate: Transform arrays into lookup objects.