Skip to content

Latest commit

 

History

History
1804 lines (1246 loc) · 31.8 KB

array.md

File metadata and controls

1804 lines (1246 loc) · 31.8 KB

Module iiris/array

The iiris/array module includes functions for working with Arrays. It is designed to be imported with a wildcard, e.g.

import * as A from 'iiris/array'

Table of contents

Basic array operations

append

<T>(value: T) => (array: T[]) => T[]

Append a new element to the end of an array.

Example
A.append(4, [1, 2, 3])
// => [1, 2, 3, 4]

See also: prepend, concat


concat

<T>(array: T[]) => (other: T[]) => T[]

Concatenate two arrays together.

Example
A.concat([1, 2, 3], [4, 5, 6])
// => [1, 2, 3, 4, 5, 6]

See also: append, prepend


forEach

<T>(fn: (value: T) => void) => (array: T[]) => T[]

Apply fn to each element of the array and return the array.

Example
A.forEach(console.log, ['h', 'i', '!'])
h
i
!
// => ['h', 'i', '!']

See also: forEachWithIndex


forEachWithIndex

<T>(fn: (index: number, value: T) => void) => (array: T[]) => T[]

Like forEach, but fn also receives the element index as the first argument.

Example
A.forEachWithIndex(console.log, ['h', 'i', '!'])
0 h
1 i
2 !
// => ['h', 'i', '!']

See also: forEach


get

(index: number) => <T>(array: T[]) => T | undefined

Return the element at index from array or undefined.

Example
A.get(0, [1, 2, 3])
// => 1

A.get(0, [])
// => undefined

See also: getOr


getOr

<T>(defaultValue: T) => (index: number) => (array: T[]) => T

Like get, but if index is not within the array bounds, defaultValue is returned instead.

Example
A.getOr(999, 0, [1, 2, 3])
// => 1

A.getOr(999, 0, [])
// => 999

A.getOr(999, 0, [undefined])
// => 999

See also: get


head

<T>(array: T[]) => T | undefined

Return the first element of the array or undefined.

Example
A.head([1, 2, 3])
// => 1

A.head([])
// => undefined

See also: tail, init, last


init

<T>(array: T[]) => T[]

Return all elements of the array except the last.

Example
A.init([1, 2, 3])
// => [1, 2]

A.init([])
// => []

See also: last, head, tail


isEmpty

<T>(array: T[]) => boolean

Check if array is empty.

Example
A.isEmpty([1, 2, 3])
// => false

A.isEmpty([])
// => true

See also: length


last

<T>(array: T[]) => T | undefined

Return the last element of the array or undefined.

Example
A.last([1, 2, 3])
// => 3

A.last([])
// => undefined

See also: init, head, tail


length

<T>(array: T[]) => number

Return the length of an array.

Example
A.length([1, 2, 3])
// => 3

A.length([])
// => 0

See also: isEmpty


modify

(index: number) => <T>(fn: (value: T) => T) => (array: T[]) => T[]

Returns a copy of array where the element at index has been replaced by applying fn to its current value. If index is not within array bounds, the array is returned unchanged.

Example
A.modify(0, (n) => n + 1, [1, 2, 3])
// => [2, 2, 3]

A.modify(-1, (n) => n + 1, [1, 2, 3])
// => [1, 2, 4]

A.modify(0, () => undefined, [1, 2, 3])
// => [2, 3]

A.modify(999, (n) => n + 1, [1, 2, 3])
// => [1, 2, 3]

See also: set, remove


prepend

<T>(value: T) => (array: T[]) => T[]

Prepend a new element to the beginning of an array.

Example
A.prepend(0, [1, 2, 3])
// => [0, 1, 2, 3]

See also: append, concat


remove

(index: number) => <T>(array: T[]) => T[]

Return a copy of array without the element at index. If index is not within the array bounds, the array is returned unchanged.

Example
A.remove(0, [1, 2, 3])
// => [2, 3]

A.remove(-1, [1, 2, 3])
// => [1, 2]

A.remove(999, [1, 2, 3])
// => [1, 2, 3]

See also: modify, set


set

(index: number) => <T>(value: T) => (array: T[]) => T[]

Returns a copy of array where the element at index has been replaced with value. If index is not within the array bounds, the array is returned unchanged.

Example
A.set(0, 999, [1, 2, 3])
// => [999, 2, 3]

A.set(-1, 999, [1, 2, 3])
// => [1, 2, 999]

A.set(999, 999, [1, 2, 3])
// => [1, 2, 3]

See also: modify, remove


tail

<T>(array: T[]) => T[]

Return all elements of the array except the first.

Example
A.tail([1, 2, 3])
// => [2, 3]

A.tail([])
// => []

See also: head, init, last


Building arrays

empty

<T>() => T[]

Create an empty array.

Example
A.empty()
// => []

See also: from, singleton


from

<T>(iterable: Iterable<T>) => T[]

Convert an iterable into an array.

A.from is like Array.from but without support for mapping the values.

Example
A.from(new Set([1, 2, 3))
// => [1, 2, 3]

See also: empty, singleton


range

(start: number) => (end: number) => number[]

Create an array of numbers between start (inclusive) and end (exclusive).

Example
A.range(0, 10)
// => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

A.range(0, 0)
// => []

See also: times, repeat


repeat

<T>(value: T) => (n: number) => T[]

Repeat the given value n times.

Example
A.repeat('a', 5)
// => ['a', 'a', 'a', 'a', 'a']

See also: range, times


singleton

<T>(values: T) => [T]

Create a singleton array containing value

Example
A.of(1)
// => [1]

A.of(1, 2, 3)
// => [1, 2, 3]

See also: from, empty


times

<T>(fn: (index: number) => T) => (n: number) => T[]

Create an array of length n by applying fn to the index of each element.

Example
A.times((n) => n * 10, 3)
// => [0, 10, 20]

See also: range, repeat


Grouping arrays by key

countBy

<T, K extends string>(keyFn: (value: T) => K) => (array: T[]) => Record<K, number>

Apply keyFn to each element in the array and return an object of counts by key.

Example
const users = [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Alice' }]

A.countBy((u) => u.name, users)
// => { Alice: 2, Bob: 1 }

See also: groupBy


groupBy

<T, K extends string>(keyFn: (value: T) => K) => (array: T[]) => Record<K, T[]>

Partition the array into an object of arrays according to keyFn.

Example
const users = [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Alice' }]

A.groupBy((u) => u.name, users)
// => { Alice: [{ name: 'Alice' }, { name: 'Alice' }], Bob: [{ name: 'Bob' }] }

See also: indexBy, countBy, groupMap, groupMapReduce


groupMap

<T, U>(mapFn: (value: T) => U) => <K extends string>(keyFn: (value: T) => K) => (array: T[]) => Record<K, U[]>

Like groupBy, but also apply mapFn to each element before adding it to the corresponding array.

Example
const users = [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: 20 },
  { name: 'Alice', age: 30 },
]
const agesByName = A.groupMap(
  (u) => u.age,
  (u) => u.name,
  users
)
// => { Alice: [10, 30], Bob: [20] }

See also: groupBy, groupMapReduce


groupMapReduce

<U>(reducer: (accumulator: U, value: U) => U) => <T>(mapFn: (value: T) => U) => <K extends string>(keyFn: (value: T) => K) => (array: T[]) => Record<K, U>

Like groupMap, but instead of returning an object of arrays, combine elements mapping to the same key with reducer.

Example
const users = [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: 20 },
  { name: 'Alice', age: 30 },
]
const sumOfAgesByName = A.groupMapReduce(
  (sum, n) => sum + n,
  (u) => u.age,
  (u) => u.name,
  users
) // => { Alice: 40, Bob: 20 }

See also: groupBy, groupMap


indexBy

<T, K extends string>(keyFn: (value: T) => K) => (array: T[]) => Record<K, T>

Apply keyFn to each element in the array and return an object of elements indexed by each key.

If multiple elements map to the same key, the last one is selected.

Example
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 1, name: 'Carol' },
]
A.indexBy((u) => u.id, users)
// => { '1': { id: 1, name: 'Carol' }, '2': { id: 2, name: 'Bob' } }

See also: groupBy


Reducing arrays

minimum

<T extends Ordered>(array: T[]) => T | undefined

Return the smallest element of array or undefined.

Example
A.minimum([1, 2, 3])
// => 1

A.minimum([])
// => undefined

See also: maximum, minimumBy


minimumBy

<T, U extends Ordered>(fn: (value: T) => U) => (array: T[]) => T | undefined

Like minimum, but fn is applied to each value before determining their ordering.

Example
const users = [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: 20 },
  { name: 'Carol', age: 30 },
]

A.minimumBy((u) => u.age, users)
// => { name: 'Alice', age: 10 }

See also: minimum, maximumBy


reduce

<T, R>(reducer: (accumulator: R, value: T) => R) => (initial: R) => (array: T[]) => R

Left-associative fold.

Combine the elements of an array in to a single value by calling reducer with the accumulated value so far and the current element. The first call to reducer receives initial as the accumulator.

If the array is empty, initial is returned.

Example
A.reduce((sum, n) => sum + n, 1, [2, 3, 4]) // equal to ((1 + 2) + 3) + 4
// => 10

See also: reduceRight


reduceRight

<T, R>(reducer: (value: T, accumulator: R) => R) => (initial: R) => (array: T[]) => R

Right-associative fold.

Combine the elements of an array in to a single value by calling reducer with the current element and the accumulated value so far. The first call to reducer receives initial as the accumulator.

If the array is empty, initial is returned.

Example
A.reduceRight((n, sum) => n + sum, 4, [1, 2, 3]) // equal to 1 + (2 + (3 + 4))
// => 10

See also: reduce


sum

(numbers: number[]) => number

Sum an array of numbers together. Returns 0 if the array is empty.

Uses the {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm Kahan summation algorithm} for minimizing numerical error.

Example
const numbers = A.repeat(0.1, 10)
// => [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]

A.sum(numbers)
// => 1

numbers.reduce((sum, n) => sum + n, 0)
// => 0.9999999999999999

See also: sumBy


sumBy

<T>(fn: (value: T) => number) => (array: T[]) => number

Like sum, but each element of the array is converted to a number by applying fn.

Example
A.sumBy((u) => u.age, [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: 20 },
])
// => 30

See also: sum


Searching arrays by value

includes

<T>(value: T) => (array: T[]) => boolean

Check if the array includes the specified value, using equals for determining equality.

Example
A.includes(1, [1, 2, 3])
// => true

A.includes(0, [1, 2, 3])
// => false

indexOf

<T>(value: T) => (array: T[]) => number

Return the index of the first element equaling value, using equals for determining equality. Returns -1 if no match can be found.

Example
A.indexOf('b', ['a', 'b', 'c', 'a', 'b', 'c'])
// => 1

A.indexOf('x', ['a', 'b', 'c', 'a', 'b', 'c'])
// => -1

See also: lastIndexOf, includes


lastIndexOf

<T>(value: T) => (array: T[]) => number

Return the index of the last element equaling value, using equals for determining equality. Returns -1 if no match can be found.

Example
A.lastIndexOf('b', ['a', 'b', 'c', 'a', 'b', 'c'])
// => 4

A.lastIndexOf('x', ['a', 'b', 'c', 'a', 'b', 'c'])
// => -1

See also: indexOf, includes


Searching arrays with a predicate

count

<T>(predicate: (value: T) => boolean) => (array: T[]) => number

Count the number of elements in the array the satisfy the predicate.

Example
A.count((n) => n > 1, [1, 2, 3])
// => 2

See also: filter


every

<T>(predicate: (value: T) => boolean) => (array: T[]) => boolean

Check if every element in the array satisfies the predicate.

Example
A.every((n) => n < 10, [1, 2, 3])
// => true

A.every((n) => n < 3, [1, 2, 3])
// => false

See also: none, some


filter

<T>(predicate: (value: T) => boolean) => (array: T[]) => T[]
<T, U>(guard: (value: T) => value is U) => (array: T[]) => U[]

Return the elements of the array that satisfy the predicate.

Example
A.filter((n) => n > 1, [1, 2, 3])
// => [2, 3]

See also: filterWithIndex, count, partition


filterWithIndex

<T>(predicate: (index: number, value: T) => boolean) => (array: T[]) => T[]

Like filter, but predicate also receives the element index as the first argument.

Example
A.filterWithIndex((i, n) => i + n === 3, [1, 2, 3])
// => [2]

See also: filter


find

<T>(predicate: (value: T) => boolean) => (array: T[]) => T | undefined
<T, U>(guard: (value: T) => value is U) => (array: T[]) => U | undefined

Find the first element in the array that satisfies the predicate.

Returns undefined if none of the elements match.

Example
A.find((c) => c !== 'a', ['a', 'b', 'c'])
// => 'b'

A.find((c) => c === 'x', ['a', 'b', 'c'])
// => undefined

See also: findLast, findIndex


findIndex

<T>(predicate: (value: T) => boolean) => (array: T[]) => number

Find the index of the first element in the array that satisfies the predicate.

Returns -1 if none of the elements satisfy the predicate.

Example
A.findIndex((c) => c !== 'a', ['a', 'b', 'c'])
// => 1

A.findIndex((c) => c === 'x', ['a', 'b', 'c'])
// => -1

See also: findLastIndex, find


findLast

<T>(predicate: (value: T) => boolean) => (array: T[]) => T | undefined
<T, U>(guard: (value: T) => value is U) => (array: T[]) => U | undefined

Find the last element in the array that satisfies the predicate.

Returns undefined if none of the elements match.

Example
A.findLast((c) => c !== 'a', ['a', 'b', 'c'])
// => 'c'

A.findLast((c) => c === 'x', ['a', 'b', 'c'])
// => undefined

See also: find, findLastIndex


findLastIndex

<T>(predicate: (value: T) => boolean) => (array: T[]) => number

Find the index of the last element in the array that satisfies the predicate.

Returns -1 if none of the elements match.

Example
A.findLastIndex((c) => c !== 'a', ['a', 'b', 'c'])
// => 2

A.findLastIndex((c) => c === 'x', ['a', 'b', 'c'])
// => -1

See also: findIndex, findLast


none

<T>(predicate: (value: T) => boolean) => (array: T[]) => boolean

Check if none of the elements in the array satisfy the predicate.

Example
A.none((n) => n > 5, [1, 2, 3])
// => true

A.none((n) => n > 5, [1, 2, 3])
// => false

See also: every, some


partition

<T>(predicate: (value: T) => boolean) => (array: T[]) => [T[], T[]]
<T, U>(guard: (value: T) => value is U) => (array: T[]) => [U[], Array<Exclude<T, U>>]

Partition the array into two arrays, the first containing the elements that satisfy the predicate and the second containing the elements that do not.

Example
const [evens, odds] = A.partition((n) => n % 2 === 0, [1, 2, 3])
// => [[2], [1, 3]]

See also: filter


some

<T>(predicate: (value: T) => boolean) => (array: T[]) => boolean

Check if some elements in the array satisfies the predicate.

Example
A.some((n) => n > 2, [1, 2, 3])
// true

A.some((n) => n > 5, [1, 2, 3])
// false

See also: every, none


Slicing arrays

drop

(n: number) => <T>(array: T[]) => T[]

Drop the first n elements of an array.

Example
A.drop(1, [1, 2, 3])
// => [2, 3]

A.drop(2, [1, 2, 3])
// => [3]

See also: dropLast, take


dropLast

(n: number) => <T>(array: T[]) => T[]

Drop the last n elements of an array.

Example
A.dropLast(1, [1, 2, 3])
// => [1, 2]

A.dropLast(2, [1, 2, 3])
// => [1]

See also: drop, takeLast


dropLastWhile

<T>(predicate: (value: T) => boolean) => (array: T[]) => T[]

Drop elements from the end of an array while predicate is satisfied.

Example
A.dropLastWhile((n) => n > 1, [1, 2, 3])
// => [1]

See also: dropWhile, takeLastWhile


dropWhile

<T>(predicate: (value: T) => boolean) => (array: T[]) => T[]

Drop elements from the beginning of an array while predicate is satisfied.

Example
A.dropWhile((n) => n === 1, [1, 2, 3])
// => [2, 3]

See also: dropLastWhile, takeWhile


slice

(start: number) => (end: number) => <T>(array: T[]) => T[]

Create a copy of array containing the elements from start (inclusive) to end (exclusive).

Example
A.slice(0, 2, [1, 2, 3])
// => [1, 2]

A.slice(1, 2, [1, 2, 3])
// => [2]

take

(n: number) => <T>(array: T[]) => T[]

Take the first n elements of an array.

Example
A.take(2, [1, 2, 3])
// => [1, 2]

See also: drop, takeLast


takeLast

<T>(n: number) => (array: T[]) => T[]

Take the last n elements of an array.

Example
A.takeLast(2, [1, 2, 3])
// => [2, 3]

See also: dropLast, take


takeLastWhile

<T>(predicate: (value: T) => boolean) => (array: T[]) => T[]

Take elements from the end of an array while predicate is satisfied.

Example
A.takeLastWhile((n) => n >= 2, [1, 2, 3])
// => [2, 3]

See also: dropLastWhile, takeWhile


takeWhile

<T>(predicate: (value: T) => boolean) => (array: T[]) => T[]

Take elements from the beginning of an array while predicate is satisfied.

Example
A.takeWhile((n) => n <= 2, [1, 2, 3])
// => [1, 2]

See also: dropWhile, takeLastWhile


Sorting arrays

sort

<T>(comparator: (first: T, second: T) => number) => (array: T[]) => T[]

Sort an array according to the comparator function.

Example
A.sort((a, b) => a - b, [3, 2, 1])
// => [1, 2, 3]

See also: sortBy, sortWith, ascend, descend


sortBy

<T, U extends Ordered>(fn: (value: T) => U) => (array: T[]) => T[]

Sort an array into ascending order by mapping each element of the array with fn.

Example
const users = [
  { name: 'Bob', age: 10 },
  { name: 'Alice', age: 20 },
]

A.sortBy((u) => u.name, users)
// => [{ name: 'Alice', age: 20 }, { name: 'Bob', age: 10 }]

A.sortBy((u) => u.age, users)
// => [{ name: 'Bob', age: 10 }, { name: 'Alice', age: 20 }]

See also: sort, sortWith


sortWith

<T>(comparators: Array<(first: T, second: T) => number>) => (array: T[]) => T[]

Sort an array according to an array of comparator functions.

The comparators are tried in order until an ordering has been found.

Example
const users = [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: 20 },
  { name: 'Alice', age: 20 },
]

A.sortWith([F.descend((u) => u.age), F.ascend((u) => u.name)], users)
// => [{ name: 'Alice', age: 20 }, { name: 'Bob', age: 20 }, { name: 'Alice', age: 10 }]

See also: sort, sortBy, ascend, descend


Transforming arrays

flatMap

<T, U>(fn: (value: T) => U[]) => (array: T[]) => U[]

Return an array containing the results of applying fn to each element in the original array and then flattening the result by one level.

Example
A.flatMap((n) => [n, n], [1, 2, 3])
// => [1, 1, 2, 2, 3, 3]

See also: map, flatten


flatten

<D extends number>(depth: D) => <T extends unknown[]>(array: T) => Array<FlatArray<T, D>>

Flatten a nested array by n levels.

Example
A.flatten(1, [1, [2, [3]]])
// => [1, 2, [3]]

A.flatten(2, [1, [2, [3]]])
// => [1, 2, 3]

See also: flatMap


intersperse

<T>(separator: T) => (array: T[]) => T[]

Return a copy of array with separator inserted between each element.

Example
A.intersperse(',', ['a', 'b', 'c'])
// => ['a', ',', 'b', ',', 'c']

A.intersperse(',', [])
// => []

See also: join


join

(separator: string) => <T>(array: T[]) => string

Convert the array to a string, inserting the separator between each element.

Example
A.join(', ', [1, 2, 3])
// => '1, 2, 3'

See also: split, intersperse


map

<T, U>(fn: (value: T) => U) => (array: T[]) => U[]

Return an array containing the results of applying fn to each element in the original array.

Example
A.map((n) => n + 1, [1, 2, 3])
// => [2, 3, 4]

See also: mapWithIndex, mapMaybe, flatMap


mapMaybe

<T, U>(fn: (value: T) => U | undefined) => (array: T[]) => U[]

Return an array containing the results of applying fn to each element in the original array, discarding any undefined values.

Example
const users = [
  { name: 'Alice', age: 10 },
  { name: 'Bob', age: undefined },
  { name: 'Carol', age: 20 },
]

A.mapMaybe((u) => u.age, users)
// => [10, 20]

See also: map


mapWithIndex

<T, U>(fn: (index: number, value: T) => U) => (array: T[]) => U[]

Like map, but fn also receives the element index as the first argument.

Example
A.mapWithIndex((i, c) => `${i}-${c}`, ['a', 'b', 'c'])
// => ['0-a', '1-b', '2-c']

See also: map


reverse

<T>(array: T[]) => T[]

Reverse an array.

Example
A.reverse([1, 2, 3])
// => [3, 2, 1]

Zipping arrays

zip

<T>(first: T[]) => <U>(second: U[]) => Array<[T, U]>

Combine the corresponding elements of two arrays into an array of pairs.

If one of the arrays is longer than the other, the extra elements are ignored.

Example
A.zip(['a', 'b', 'c'], [1, 2, 3])
// => [['a', 1], ['b', 2], ['c', 3]]

See also: zipWith, zipObject


zipObject

<K extends string>(keys: K[]) => <T>(values: T[]) => Record<K, T>

Combine an array of keys and values into an object.

If one of the arrays is longer than the other, its extra elements are ignored.

Example
A.zipObject(['a', 'b', 'c'], [1, 2, 3])
// => { a: 1, b: 2, c: 3 }

See also: zip, fromEntries


zipWith

<T, U, R>(fn: (value: T, other: U) => R) => (first: T[]) => (second: U[]) => R[]

Like zip, but the elements are combined with fn instead of constructing a pair.

Example
A.zipWith((a, b) => a + b, [1, 2, 3], [4, 5, 6])
// => [5, 7, 9]

See also: zip