UNPKG

3.72 kBJavaScriptView Raw
1/**
2 * Utility module to work with Arrays.
3 *
4 * @module array
5 */
6
7import * as set from './set.js'
8
9/**
10 * Return the last element of an array. The element must exist
11 *
12 * @template L
13 * @param {ArrayLike<L>} arr
14 * @return {L}
15 */
16export const last = arr => arr[arr.length - 1]
17
18/**
19 * @template C
20 * @return {Array<C>}
21 */
22export const create = () => /** @type {Array<C>} */ ([])
23
24/**
25 * @template D
26 * @param {Array<D>} a
27 * @return {Array<D>}
28 */
29export const copy = a => /** @type {Array<D>} */ (a.slice())
30
31/**
32 * Append elements from src to dest
33 *
34 * @template M
35 * @param {Array<M>} dest
36 * @param {Array<M>} src
37 */
38export const appendTo = (dest, src) => {
39 for (let i = 0; i < src.length; i++) {
40 dest.push(src[i])
41 }
42}
43
44/**
45 * Transforms something array-like to an actual Array.
46 *
47 * @function
48 * @template T
49 * @param {ArrayLike<T>|Iterable<T>} arraylike
50 * @return {T}
51 */
52export const from = Array.from
53
54/**
55 * True iff condition holds on every element in the Array.
56 *
57 * @function
58 * @template ITEM
59 * @template {ArrayLike<ITEM>} ARR
60 *
61 * @param {ARR} arr
62 * @param {function(ITEM, number, ARR):boolean} f
63 * @return {boolean}
64 */
65export const every = (arr, f) => {
66 for (let i = 0; i < arr.length; i++) {
67 if (!f(arr[i], i, arr)) {
68 return false
69 }
70 }
71 return true
72}
73
74/**
75 * True iff condition holds on some element in the Array.
76 *
77 * @function
78 * @template S
79 * @template {ArrayLike<S>} ARR
80 * @param {ARR} arr
81 * @param {function(S, number, ARR):boolean} f
82 * @return {boolean}
83 */
84export const some = (arr, f) => {
85 for (let i = 0; i < arr.length; i++) {
86 if (f(arr[i], i, arr)) {
87 return true
88 }
89 }
90 return false
91}
92
93/**
94 * @template ELEM
95 *
96 * @param {ArrayLike<ELEM>} a
97 * @param {ArrayLike<ELEM>} b
98 * @return {boolean}
99 */
100export const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])
101
102/**
103 * @template ELEM
104 * @param {Array<Array<ELEM>>} arr
105 * @return {Array<ELEM>}
106 */
107export const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))
108
109/**
110 * @template T
111 * @param {number} len
112 * @param {function(number, Array<T>):T} f
113 * @return {Array<T>}
114 */
115export const unfold = (len, f) => {
116 const array = new Array(len)
117 for (let i = 0; i < len; i++) {
118 array[i] = f(i, array)
119 }
120 return array
121}
122
123/**
124 * @template T
125 * @template RESULT
126 * @param {Array<T>} arr
127 * @param {RESULT} seed
128 * @param {function(RESULT, T, number):RESULT} folder
129 */
130export const fold = (arr, seed, folder) => arr.reduce(folder, seed)
131
132export const isArray = Array.isArray
133
134/**
135 * @template T
136 * @param {Array<T>} arr
137 * @return {Array<T>}
138 */
139export const unique = arr => from(set.from(arr))
140
141/**
142 * @template T
143 * @template M
144 * @param {ArrayLike<T>} arr
145 * @param {function(T):M} mapper
146 * @return {Array<T>}
147 */
148export const uniqueBy = (arr, mapper) => {
149 /**
150 * @type {Set<M>}
151 */
152 const happened = set.create()
153 /**
154 * @type {Array<T>}
155 */
156 const result = []
157 for (let i = 0; i < arr.length; i++) {
158 const el = arr[i]
159 const mapped = mapper(el)
160 if (!happened.has(mapped)) {
161 happened.add(mapped)
162 result.push(el)
163 }
164 }
165 return result
166}
167
168/**
169 * @template {ArrayLike<any>} ARR
170 * @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER
171 * @param {ARR} arr
172 * @param {MAPPER} mapper
173 * @return {Array<MAPPER extends function(...any): infer M ? M : never>}
174 */
175export const map = (arr, mapper) => {
176 /**
177 * @type {Array<any>}
178 */
179 const res = Array(arr.length)
180 for (let i = 0; i < arr.length; i++) {
181 res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr))
182 }
183 return /** @type {any} */ (res)
184}