Source

array/index.ts

import type { Dictionary } from "../types";

/**
 * Convert an array to an object
 * @method
 * @param arr {Array<T>} The array to convert
 * @param key {string=} The key as object's key
 * @return {Record<string, T>}
 *
 * @example
 * toObject([{ id: 1 , value: "foo" }, { id: 2, value: "bar" }], "id")
 * // {"1": { id: 1 , value: "foo" }, "2": { id: 2, value: "bar" }}
 * @category Array
 * @version v0.1.0
 */
export const toObject = <T>(
  arr: Array<T>,
  key?: string | boolean,
): Dictionary<T> => {
  return arr.reduce((acc, each: T | Dictionary<T>, idx) => {
    if (!each) return acc;
    if (key === true) {
      acc[idx] = each as T;
    } else if (key && (each as Dictionary<T>)[key]) {
      acc[(each as never)[key]] = each as T;
    } else {
      acc[JSON.stringify(each)] = each as T;
    }
    return acc;
  }, {} as Dictionary<T>);
};

/**
 * Unique array's elements
 * @method
 * @param arr {Array<T>} The array to be uniquefy
 * @return {Array<T>} The unique array
 *
 * @example
 * uniqueArray([1, 1, 2, 2])
 * // [1, 2]
 * @category Array
 * @version v0.1.0
 */
export const uniqueArray = <T>(arr: T[]): T[] => [...new Set(arr)];

/**
 * Unique array of object's elements by key
 * @method
 * @param arr {Array<T>} The array of object to be uniquefy
 * @param key {string} The key to inspect
 * @return {Array<T>} The unique array of object
 * @example
 * uniqueArray([{ x: 1, y: 1 }, { x: 2, y: 1 }, { x: 2, y: 2 }])
 * // [{ x: 1, y: 1}, { x: 2, y: 2 }]
 * @category Array
 * @version v0.1.0
 */
export const uniqueArrayByKey = <T extends Record<string, any>>(
  arr: T[],
  key: string,
): T[] => [...new Map(arr.map((v) => [v[key], v])).values()];

/**
 * Move an element to provided index
 * @method
 * @param arr {Array<T>} The array to modify
 * @param from {number} The index of the element
 * @param to {number} The index of destination
 * @return {Array<T>}
 * @example
 * move([1, 2, 3, 4], 0, 3)
 * // [2, 3, 4, 1]
 * @category Array
 * @version v0.1.0
 */
export const move = <T>(arr: T[], from: number, to: number): T[] => {
  arr.splice(to, 0, arr.splice(from, 1)[0]);
  return arr;
};

/**
 * Cartesian product of multiple arrays
 *
 * Credits: https://gist.github.com/ssippe/1f92625532eef28be6974f898efb23ef#gistcomment-3530882
 * @method
 * @param sets {...T[][]} The array(s) to be combine
 * @return {T[][]} Two-dimensional array of combination
 * @example
 * cartesian([1,2],[10,20],[100,200,300])
 * // [ [ 1, 10, 100 ],
 // [ 1, 10, 200 ],
 // [ 1, 10, 300 ],
 // [ 1, 20, 200 ],
 // [ 1, 20, 300 ],
 // [ 2, 10, 100 ],
 // [ 1, 20, 100 ],
 // [ 2, 10, 200 ],
 // [ 2, 10, 300 ],
 // [ 2, 20, 100 ],
 // [ 2, 20, 200 ],
 // [ 2, 20, 300 ] ]
 * @category Array
 * @version v0.1.0
 */
export const cartesian = <T>(...sets: T[][]): T[][] =>
  sets.reduce<T[][]>(
    (accSets, set) =>
      accSets.flatMap((accSet) => set.map((value) => [...accSet, value])),
    [[]],
  );

/**
 * Get the difference of two array
 * @method
 * @param left {T[]} The array to inspect
 * @param right {T[]} The array to exclude
 * @param key {string} The key to inspect
 * @return {T[]} The excluded array of item
 * @example
 * differenceBy([{ x: 1 }, { x: 2 }], [{ x: 2 }, { x: 3 }], "x")
 * // [{ x: 1 }]
 * @category Array
 * @version v0.1.0
 */
export const differenceBy = <T>(left: T[], right: T[], key: string): T[] => {
  return left.filter(
    (v) => !right.some((x) => (x as any)[key] === (v as any)[key]),
  );
};

/**
 * Get the difference of two array of object
 * @method
 * @param left {T[]} The array to inspect
 * @param right {T[]} The array to exclude
 * @return {T[]} The excluded array of item
 * @example
 * difference([1, 2], [2, 3])
 * // [1]
 * @category Array
 * @version v0.1.0
 */
export const difference = <T>(left: T[], right: T[]): T[] => {
  return left.filter((v) => !right.some((x) => x === v));
};