node-comfortv2.0.0

nc.arr

Array helpers. None of them mutate what you pass in, and item types carry through (chunk(numbers, 2) is a number[][]). Many take an iteratee: a property name, which your editor completes, or a function.

const { arr } = require("@ix-xs/node-comfort");
import { chunk } from "@ix-xs/node-comfort/arr";
arr.chunk([1, 2, 3, 4, 5], 2);          // [[1, 2], [3, 4], [5]]
arr.groupBy(users, "role");             // { admin: [...], user: [...] }
arr.sortBy(users, ["lastName", "age"]);
GuideExplanations and examples for nc.arr.
Read the guide →

Functions

nc.arr.chunk()

chunk<T>(array: readonly T[], size: number): T[][]

Splits an array into groups of size items. The last group can be shorter.

Parameters

NameType
arrayreadonly T[]
sizenumber

Returns T[][]

Example

arr.chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
arr.chunk(emails, 100).forEach(sendBatch);

nc.arr.windows()

windows<T>(array: readonly T[], size: number, step?: number): T[][]

Sliding windows of size items, moving by step. Good for moving averages and comparing neighbours.

Parameters

NameTypeDescription
arrayreadonly T[]
sizenumber
stepoptionalnumberDefault: 1

Returns T[][]

Example

arr.windows([1, 2, 3, 4], 2);       // [[1, 2], [2, 3], [3, 4]]
arr.windows([1, 2, 3, 4, 5], 3, 2); // [[1, 2, 3], [3, 4, 5]]

nc.arr.first()2 overloads

first<T>(array: readonly T[]): T | undefined
first<T>(array: readonly T[], n: number): T[]

The first item, or the first n items.

Parameters

NameType
arrayreadonly T[]
nnumber

Returns T[]

Example

arr.first([1, 2, 3]);    // 1
arr.first([1, 2, 3], 2); // [1, 2]

nc.arr.last()2 overloads

last<T>(array: readonly T[]): T | undefined
last<T>(array: readonly T[], n: number): T[]

The last item, or the last n items.

Parameters

NameType
arrayreadonly T[]
nnumber

Returns T[]

Example

arr.last([1, 2, 3]);    // 3
arr.last([1, 2, 3], 2); // [2, 3]

nc.arr.paginate()

paginate<T>(array: readonly T[], page?: number, perPage?: number): Page<T>

One page of an array, with what you need to draw pagination controls. Pages start at 1; an out-of-range page is brought back into range.

Parameters

NameTypeDescription
arrayreadonly T[]
pageoptionalnumberDefault: 1
perPageoptionalnumberDefault: 20

Returns Page<T>

Example

arr.paginate(products, 2, 20);
// { items: [...], page: 2, perPage: 20, total: 95, pages: 5, hasPrev: true, hasNext: true }

nc.arr.unique()

unique<T>(array: readonly T[], iteratee?: Iteratee<T>): T[]

Removes duplicates. With an iteratee, items that give the same value are duplicates; the first one is kept.

Parameters

NameType
arrayreadonly T[]
iterateeoptionalIteratee<T>

Returns T[]

Example

arr.unique([1, 1, 2, 3]);                  // [1, 2, 3]
arr.unique(users, "email");                // one user per email
arr.unique(tags, (t) => t.toLowerCase());

nc.arr.groupBy()

groupBy<T>(array: readonly T[], iteratee: Iteratee<T>): Record<string, T[]>

Groups items by key.

Parameters

NameType
arrayreadonly T[]
iterateeIteratee<T>

Returns Record<string, T[]>

Example

arr.groupBy(users, "role"); // { admin: [...], user: [...] }
arr.groupBy([1, 2, 3, 4], (n) => (n % 2 ? "odd" : "even")); // { odd: [1, 3], even: [2, 4] }

nc.arr.keyBy()

keyBy<T>(array: readonly T[], iteratee: Iteratee<T>): Record<string, T>

Indexes items by key. If two items share a key, the last one wins.

Parameters

NameType
arrayreadonly T[]
iterateeIteratee<T>

Returns Record<string, T>

Example

const byId = arr.keyBy(users, "id");
byId[42]; // user 42

nc.arr.toMap()

toMap<T, V = T>(array: readonly T[], key: Iteratee<T>, value?: ((item: T, index: number) => V) | undefined): Map<any, V>

Builds a Map from an array. Unlike keyBy(), keys keep their type.

Parameters

NameTypeDescription
arrayreadonly T[]
keyIteratee<T>
valueoptional(item: T, index: number) => VThe value to store. Defaults to the item.

Returns Map<any, V>

Example

arr.toMap(users, "id");                 // Map<number, User>
arr.toMap(users, "id", (u) => u.name);  // Map<number, string>

nc.arr.countBy()

countBy<T>(array: readonly T[], iteratee?: Iteratee<T>): Record<string, number>

Counts items per key.

Parameters

NameTypeDescription
arrayreadonly T[]
iterateeoptionalIteratee<T>Defaults to the item itself.

Returns Record<string, number>

Example

arr.countBy(["a", "b", "a"]);  // { a: 2, b: 1 }
arr.countBy(users, "country"); // { FR: 12, US: 7 }

nc.arr.count()

count<T>(array: readonly T[], predicate: (item: T, index: number) => unknown): number

Counts the items that pass a test.

Parameters

NameType
arrayreadonly T[]
predicate(item: T, index: number) => unknown

Returns number

Example

arr.count(users, (u) => u.active);

nc.arr.partition()

partition<T>(array: readonly T[], predicate: (item: T, index: number) => unknown): [T[], T[]]

Splits items into those that pass a test and those that don't.

Parameters

NameType
arrayreadonly T[]
predicate(item: T, index: number) => unknown

Returns [T[], T[]]

Example

const [adults, minors] = arr.partition(people, (p) => p.age >= 18);

nc.arr.pluck()

pluck<T, K extends keyof T>(array: readonly T[], key: K): T[K][]

Takes one property from every item.

Parameters

NameType
arrayreadonly T[]
keyK

Returns Array<T[K]>

Example

arr.pluck(users, "email"); // ["ada@x.io", "bob@x.io"]

nc.arr.sortBy()

sortBy<T>(array: readonly T[], keys: SortKey<T> | SortKey<T>[], order?: "asc" | "desc" | SortByOptions): T[]

Sorts by one or more keys, each with its own direction if you like. The sort is stable and null/undefined always go last.

Parameters

NameTypeDescription
arrayreadonly T[]
keysSortKey<T> | Array<SortKey<T>>
orderoptional"asc" | "desc" | SortByOptionsDefault: "asc"

Returns T[]

Example

arr.sortBy(users, "age");                         // youngest first
arr.sortBy(users, "age", "desc");                 // oldest first
arr.sortBy(users, [["age", "desc"], "lastName"]);
arr.sortBy(files, "name", { natural: true });     // "file2" before "file10"

nc.arr.shuffle()

shuffle<T>(array: readonly T[]): T[]

A shuffled copy (Fisher-Yates).

Parameters

NameType
arrayreadonly T[]

Returns T[]

nc.arr.sample()

sample<T>(array: readonly T[]): T | undefined

One random item, or undefined if the array is empty.

Parameters

NameType
arrayreadonly T[]

Returns T | undefined

nc.arr.sampleSize()

sampleSize<T>(array: readonly T[], n: number): T[]

n random items, never the same one twice.

Parameters

NameType
arrayreadonly T[]
nnumber

Returns T[]

Example

arr.sampleSize(players, 3);

nc.arr.rotate()

rotate<T>(array: readonly T[], n?: number): T[]

Rotates items. Positive n moves items from the start to the end, negative n the other way.

Parameters

NameTypeDescription
arrayreadonly T[]
noptionalnumberDefault: 1

Returns T[]

Example

arr.rotate([1, 2, 3, 4], 1);  // [2, 3, 4, 1]
arr.rotate([1, 2, 3, 4], -1); // [4, 1, 2, 3]

nc.arr.move()

move<T>(array: readonly T[], from: number, to: number): T[]

Moves one item to another position. Negative indexes count from the end.

Parameters

NameType
arrayreadonly T[]
fromnumber
tonumber

Returns T[]

Example

arr.move(["a", "b", "c"], 0, 2); // ["b", "c", "a"]

nc.arr.swap()

swap<T>(array: readonly T[], i: number, j: number): T[]

Swaps two items.

Parameters

NameType
arrayreadonly T[]
inumber
jnumber

Returns T[]

Example

arr.swap(["a", "b", "c"], 0, 2); // ["c", "b", "a"]

nc.arr.difference()

difference<T>(array: readonly T[], ...others: (readonly T[])[]): T[]

Items of array that appear in none of the others.

Parameters

NameType
arrayreadonly T[]
...others...ReadonlyArray<T>

Returns T[]

Example

arr.difference([1, 2, 3, 4], [2, 4]); // [1, 3]

nc.arr.intersection()

intersection<T>(...arrays: (readonly T[])[]): T[]

Items present in every array, without duplicates.

Parameters

NameType
...arrays...ReadonlyArray<T>

Returns T[]

Example

arr.intersection([1, 2, 3], [2, 3, 4], [3, 2]); // [2, 3]

nc.arr.union()

union<T>(...arrays: (readonly T[])[]): T[]

Items present in any array, without duplicates.

Parameters

NameType
...arrays...ReadonlyArray<T>

Returns T[]

Example

arr.union([1, 2], [2, 3], [3, 4]); // [1, 2, 3, 4]

nc.arr.without()

without<T>(array: readonly T[], ...values: T[]): T[]

A copy without the given values. NaN works too.

Parameters

NameType
arrayreadonly T[]
...values...T

Returns T[]

Example

arr.without([1, 2, 3, 2], 2); // [1, 3]

nc.arr.remove()

remove<T>(array: readonly T[], predicate: (item: T, index: number) => unknown): T[]

A copy without the items that pass the test.

Parameters

NameType
arrayreadonly T[]
predicate(item: T, index: number) => unknown

Returns T[]

Example

arr.remove([1, 2, 3, 4], (n) => n % 2 === 0); // [1, 3]

nc.arr.compact()

compact<T>(array: readonly T[]): Exclude<T, false | "" | 0 | 0n | null | undefined>[]

Removes falsy values (false, null, undefined, 0, "", NaN).

Parameters

NameType
arrayreadonly T[]

Returns Array<Exclude<T, false | 0 | 0n | "" | null | undefined>>

Example

arr.compact([0, 1, false, 2, "", 3, null]); // [1, 2, 3]

nc.arr.toggle()

toggle<T>(array: readonly T[], item: T): T[]

Adds the item if it's missing, removes it if it's there. Handy for multi-select state.

Parameters

NameType
arrayreadonly T[]
itemT

Returns T[]

Example

arr.toggle(["a", "b"], "b"); // ["a"]
arr.toggle(["a"], "b");      // ["a", "b"]

nc.arr.upsert()

upsert<T>(array: readonly T[], item: T, identity: Iteratee<T>): T[]

Replaces the item with the same identity, or appends it if there's none.

Parameters

NameTypeDescription
arrayreadonly T[]
itemT
identityIteratee<T>What makes two items "the same", like "id".

Returns T[]

Example

arr.upsert(users, { id: 2, name: "Bob" }, "id");

nc.arr.insert()

insert<T>(array: readonly T[], index: number, ...items: T[]): T[]

Inserts items at an index. Negative indexes count from the end.

Parameters

NameType
arrayreadonly T[]
indexnumber
...items...T

Returns T[]

Example

arr.insert(["a", "d"], 1, "b", "c"); // ["a", "b", "c", "d"]

nc.arr.flatten()

flatten<T, D extends number = 1>(array: readonly T[], depth?: D): FlatArray<T[], D>[]

Flattens nested arrays, one level by default.

Parameters

NameType
arrayreadonly T[]
depthoptionalD

Returns FlatArray<T[], D>[]

Example

arr.flatten([1, [2, [3, [4]]]]);           // [1, 2, [3, [4]]]
arr.flatten([1, [2, [3, [4]]]], Infinity); // [1, 2, 3, 4]

nc.arr.zip()

zip<T>(...arrays: (readonly T[])[]): (T | undefined)[][]

Pairs items by position. Shorter arrays leave undefined holes.

Parameters

NameType
...arrays...ReadonlyArray<T>

Returns Array<Array<T | undefined>>

Example

arr.zip(["a", "b"], [1, 2]); // [["a", 1], ["b", 2]]

nc.arr.unzip()

unzip<T>(tuples: readonly (readonly T[])[]): (T | undefined)[][]

The opposite of zip(): rows become columns.

Parameters

NameType
tuplesReadonlyArray<ReadonlyArray<T>>

Returns Array<Array<T | undefined>>

Example

arr.unzip([["a", 1], ["b", 2]]); // [["a", "b"], [1, 2]]

nc.arr.interleave()

interleave<T>(...arrays: (readonly T[])[]): T[]

Takes items from each array in turn, then appends the rest.

Parameters

NameType
...arrays...ReadonlyArray<T>

Returns T[]

Example

arr.interleave([1, 3, 5], [2, 4]); // [1, 2, 3, 4, 5]

nc.arr.cartesian()

cartesian<T>(...arrays: (readonly T[])[]): T[][]

Every combination of one item from each array.

Parameters

NameType
...arrays...ReadonlyArray<T>

Returns T[][]

Example

arr.cartesian(["S", "M"], ["red", "blue"]);
// [["S", "red"], ["S", "blue"], ["M", "red"], ["M", "blue"]]

nc.arr.times()

times<T>(n: number, value?: T | ((index: number) => T) | undefined): T[]

An array of n items, from a value or a function of the index.

Parameters

NameType
nnumber
valueoptionalT | ((index: number) => T)

Returns T[]

Example

arr.times(3, "x");          // ["x", "x", "x"]
arr.times(3, (i) => i * 2); // [0, 2, 4]

nc.arr.sumBy()

sumBy<T>(array: readonly T[], iteratee?: Iteratee<T>): number

Adds up a number from each item. Non-numbers count as 0.

Parameters

NameType
arrayreadonly T[]
iterateeoptionalIteratee<T>

Returns number

Example

arr.sumBy(cart, "price");
arr.sumBy(cart, (item) => item.price * item.quantity);

nc.arr.averageBy()

averageBy<T>(array: readonly T[], iteratee?: Iteratee<T>): number

The average of a number from each item, or 0 for an empty array.

Parameters

NameType
arrayreadonly T[]
iterateeoptionalIteratee<T>

Returns number

Example

arr.averageBy(reviews, "rating"); // 4.3

nc.arr.maxBy()

maxBy<T>(array: readonly T[], iteratee?: Iteratee<T>): T | undefined

The item with the highest value.

Parameters

NameType
arrayreadonly T[]
iterateeoptionalIteratee<T>

Returns T | undefined

Example

arr.maxBy(players, "score");

nc.arr.minBy()

minBy<T>(array: readonly T[], iteratee?: Iteratee<T>): T | undefined

The item with the lowest value.

Parameters

NameType
arrayreadonly T[]
iterateeoptionalIteratee<T>

Returns T | undefined

Example

arr.minBy(products, "price");

Types

Import any of them in TypeScript with import type { Iteratee } from "@ix-xs/node-comfort", or in JavaScript with import("@ix-xs/node-comfort").Iteratee.

Iteratee

How to get a value out of an item: a property name, or a function (item, index) => value.

type Iteratee = (T extends object ? keyof T & (string | number) : never) | ((item: T, index: number) => unknown)

Page

A page returned by paginate().

PropertyTypeDescription
itemsT[]The items on this page.
pagenumberThe page number, starting at 1.
perPagenumber
totalnumberTotal number of items.
pagesnumberNumber of pages, at least 1.
hasPrevboolean
hasNextboolean

SortByOptions

Options for sortBy().

PropertyTypeDescription
orderoptional"asc" | "desc"Direction for keys that don't set their own. Defaults to "asc".
naturaloptionalbooleanSort text like a person would: ignore case, respect accents, "item2" before "item10".
localeoptionalstringLanguage used by natural. Defaults to the system's.

SortKey

A sort key for sortBy(): an iteratee, or [iteratee, "asc" | "desc"] to give that key its own direction.

type SortKey = Iteratee<T> | [Iteratee<T>, "asc" | "desc"]
node-comfort v2.0.0View the source