atomic-fns 0.3.5 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +1 -12
  2. package/{core → dist}/collections/BTree.d.ts +6 -6
  3. package/{core → dist}/collections/BTree.js +17 -17
  4. package/{core → dist}/collections/Heap.d.ts +3 -3
  5. package/{core → dist}/collections/Heap.js +0 -0
  6. package/dist/collections/LRUCache.d.ts +80 -0
  7. package/dist/collections/LRUCache.js +126 -0
  8. package/{core → dist}/collections/SortedMap.d.ts +2 -2
  9. package/{core → dist}/collections/SortedMap.js +0 -0
  10. package/{core → dist}/collections/SortedSet.d.ts +3 -3
  11. package/{core → dist}/collections/SortedSet.js +1 -1
  12. package/{core → dist}/collections/SortedTree.d.ts +3 -3
  13. package/{core → dist}/collections/SortedTree.js +1 -1
  14. package/{core → dist}/collections/SplayTree.d.ts +5 -5
  15. package/{core → dist}/collections/SplayTree.js +0 -0
  16. package/{core → dist}/collections/abc.d.ts +0 -0
  17. package/{core → dist}/collections/abc.js +0 -0
  18. package/{core → dist}/collections/deque.d.ts +7 -7
  19. package/{core → dist}/collections/deque.js +6 -8
  20. package/{core → dist}/collections/frozenset.d.ts +0 -0
  21. package/{core → dist}/collections/frozenset.js +3 -6
  22. package/{core → dist}/collections/index.d.ts +207 -105
  23. package/{core → dist}/collections/index.js +179 -436
  24. package/{core → dist}/functools/index.d.ts +30 -16
  25. package/{core → dist}/functools/index.js +34 -12
  26. package/dist/globals/decimal.d.ts +142 -0
  27. package/dist/globals/decimal.js +371 -0
  28. package/{core → dist}/globals/index.d.ts +26 -25
  29. package/{core → dist}/globals/index.js +16 -37
  30. package/dist/i18n/currency.d.ts +24 -0
  31. package/dist/i18n/currency.js +85 -0
  32. package/dist/i18n/date/index.d.ts +204 -0
  33. package/dist/i18n/date/index.js +530 -0
  34. package/dist/i18n/date/utils.d.ts +65 -0
  35. package/dist/i18n/date/utils.js +290 -0
  36. package/dist/i18n/duration.d.ts +112 -0
  37. package/dist/i18n/duration.js +392 -0
  38. package/dist/i18n/format.d.ts +26 -0
  39. package/dist/i18n/format.js +495 -0
  40. package/{core → dist}/i18n/index.d.ts +2 -1
  41. package/{core → dist}/i18n/index.js +2 -1
  42. package/{core → dist}/index.d.ts +0 -0
  43. package/{core → dist}/index.js +0 -0
  44. package/{core → dist}/itertools/index.d.ts +74 -46
  45. package/{core → dist}/itertools/index.js +28 -56
  46. package/{core → dist}/math/index.d.ts +9 -10
  47. package/{core → dist}/math/index.js +3 -1
  48. package/{core → dist}/operators/index.d.ts +4 -4
  49. package/{core → dist}/operators/index.js +2 -8
  50. package/{core → dist}/random/index.d.ts +1 -1
  51. package/{core → dist}/random/index.js +5 -5
  52. package/package.json +28 -42
  53. package/.editorconfig +0 -12
  54. package/.esdoc.json +0 -27
  55. package/.eslintignore +0 -1
  56. package/.eslintrc.json +0 -35
  57. package/.firebaserc +0 -5
  58. package/.prettierrc +0 -19
  59. package/core/collections/BTree.ts +0 -1340
  60. package/core/collections/Heap.ts +0 -189
  61. package/core/collections/LRUCache.d.ts +0 -152
  62. package/core/collections/LRUCache.js +0 -409
  63. package/core/collections/LRUCache.ts +0 -486
  64. package/core/collections/SortedMap.ts +0 -146
  65. package/core/collections/SortedSet.ts +0 -110
  66. package/core/collections/SortedTree.ts +0 -160
  67. package/core/collections/SplayTree.ts +0 -354
  68. package/core/collections/abc.ts +0 -176
  69. package/core/collections/deque.ts +0 -338
  70. package/core/collections/frozenset.ts +0 -37
  71. package/core/collections/index.ts +0 -1024
  72. package/core/collections/test.html +0 -10
  73. package/core/collections/typedArrays.d.ts +0 -31
  74. package/core/collections/typedArrays.js +0 -143
  75. package/core/collections/typedArrays.ts +0 -163
  76. package/core/functools/index.ts +0 -260
  77. package/core/globals/index.ts +0 -481
  78. package/core/i18n/date/format.d.ts +0 -16
  79. package/core/i18n/date/format.js +0 -307
  80. package/core/i18n/date/format.ts +0 -343
  81. package/core/i18n/date/index.d.ts +0 -224
  82. package/core/i18n/date/index.js +0 -387
  83. package/core/i18n/date/index.ts +0 -471
  84. package/core/i18n/date/test.html +0 -67
  85. package/core/i18n/index.ts +0 -8
  86. package/core/index.ts +0 -8
  87. package/core/itertools/index.ts +0 -494
  88. package/core/math/index.ts +0 -152
  89. package/core/operators/index.ts +0 -310
  90. package/core/random/index.ts +0 -66
  91. package/firebase.json +0 -10
  92. package/jasmine.json +0 -14
  93. package/tests/BTree.spec.ts +0 -143
  94. package/tests/Cache.spec.ts +0 -161
  95. package/tests/Heap.spec.ts +0 -66
  96. package/tests/SortedMap.spec.ts +0 -144
  97. package/tests/SortedSet.spec.ts +0 -84
  98. package/tests/SortedTree.spec.ts +0 -164
  99. package/tests/SplayTree.spec.ts +0 -121
  100. package/tests/collections.spec.ts +0 -288
  101. package/tests/deque.spec.ts +0 -107
  102. package/tests/globals.spec.ts +0 -270
  103. package/tests/itertools.spec.ts +0 -266
  104. package/tests/math.spec.ts +0 -25
  105. package/tests/operators.spec.ts +0 -40
  106. package/tests/random.spec.ts +0 -46
  107. package/tsconfig.json +0 -126
  108. package/tsconfig.node.json +0 -18
  109. package/tsconfig.xo.json +0 -9
@@ -3,8 +3,7 @@
3
3
  *
4
4
  * @module Collections
5
5
  */
6
- import { partial } from '../functools/index.js';
7
- import { call, get, isArray, isArrayLike, isBool, isEmpty, isFunction, isIterable, isNull, isNumber, isObject, isString, isSymbol, keys, set } from '../globals/index.js';
6
+ import { call, get, isArray, isArrayLike, isBool, isEmpty, isFunction, isIterable, isNull, isNumber, isObject, isString, keys, set } from '../globals/index.js';
8
7
  import { enumerate } from '../itertools/index.js';
9
8
  import { compare, eq, id } from '../operators/index.js';
10
9
  export * from './abc.js';
@@ -13,12 +12,12 @@ export * from './deque.js';
13
12
  export * from './frozenset.js';
14
13
  export * from './Heap.js';
15
14
  export * from './LRUCache.js';
16
- export * from './SortedSet.js';
17
15
  export * from './SortedMap.js';
16
+ export * from './SortedSet.js';
18
17
  export * from './SortedTree.js';
19
18
  export * from './SplayTree.js';
20
19
  export function compact(arr) {
21
- if (arr == null)
20
+ if (!arr)
22
21
  return;
23
22
  if (Array.isArray(arr))
24
23
  return arr.filter((x) => !isEmpty(x));
@@ -30,9 +29,9 @@ export function compact(arr) {
30
29
  }
31
30
  return result;
32
31
  }
33
- export function count(iterable, func) {
32
+ export function count(obj, func) {
34
33
  const counters = {};
35
- forEach(iterable, (value, key) => {
34
+ forEach(obj, (value, key) => {
36
35
  const result = func(value, key);
37
36
  counters[result] = get(result, counters, 0) + 1;
38
37
  });
@@ -42,116 +41,34 @@ export function count(iterable, func) {
42
41
  * Creates a function that can be used to create named tuple-like objects.
43
42
  * @example
44
43
  ```js
45
- * let Point = namedtuple('x', 'y', 'z')
46
- * let userObj = User(0, 0, 0)
47
- * // => {x: 0, y: 0, z: 0}
44
+ let Point = namedtuple('x', 'y', 'z')
45
+ let userObj = User(0, 0, 0)
46
+ // {x: 0, y: 0, z: 0}
48
47
  ```
49
48
  * @param fields - A list of field names
50
49
  * @returns A function that can be called with the field values
51
50
  */
52
- export function namedtuple(...fields) {
53
- return (...args) => fields.reduce((prev, f, i) => set(f, prev, args[i], false, true), {});
54
- }
55
- /**
56
- * Iterates over elements of collection, returning an array of all elements where predicate returns truthy value.
57
- *
58
- * The predicate is invoked with three arguments: `(value, index|key, arr)`.
59
- *
60
- * @example
61
- ```js
62
- * let users = [
63
- { 'user': 'barney', 'age': 36, 'active': true },
64
- { 'user': 'fred', 'age': 40, 'active': false }
65
- ]
66
-
67
- filter(users, o => !o.active)
68
- // => objects for ['fred']
69
-
70
- // The shape iteratee shorthand.
71
- filter(users, { age: 36, active: true })
72
- // => objects for ['barney']
73
-
74
- // The property iteratee shorthand.
75
- filter(users, 'active')
76
- // => objects for ['barney']
77
- ```
78
- * @param {Array} arr The collection to iterate over
79
- * @param {Function} fn The predicate function invoked for each item
80
- * @returns {Array} The new filtered array
81
- */
51
+ export const namedtuple = (...fields) => (...args) => fields.reduce((prev, f, i) => set(f, prev, args[i], false, true), {});
82
52
  export function filter(arr, fn = isNull) {
83
- if (Array.isArray(arr)) {
84
- if (isFunction(fn))
85
- return arr.filter(fn);
86
- if (isNumber(fn) || isString(fn) || isSymbol(fn))
87
- return arr.filter((x) => get(fn, x));
88
- if (isObject(fn))
89
- return arr.filter(matches(fn));
90
- }
53
+ if (!arr)
54
+ return;
55
+ const predicate = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
56
+ const results = [];
57
+ forEach(arr, (value, key) => {
58
+ if (predicate(value, key, arr))
59
+ results.push(value);
60
+ });
61
+ return results;
91
62
  }
92
- /**
93
- * Iterates over elements of collection, returning the first element where predicate returns truthy value. The predicate is invoked with three arguments: `(value, index|key, collection)`.
94
- * @example
95
- ```js
96
- let users = [
97
- { 'user': 'barney', 'age': 36, 'active': true },
98
- { 'user': 'fred', 'age': 40, 'active': false },
99
- { 'user': 'pebbles', 'age': 1, 'active': true }
100
- ]
101
-
102
- find(users, (o) => o.age < 40)
103
- // => object for 'barney'
104
-
105
- // The shape iteratee shorthand.
106
- find(users, { 'age': 1, 'active': true })
107
- // => object for 'pebbles'
108
-
109
- // The `property` iteratee shorthand.
110
- find(users, 'active')
111
- // => object for 'barney'
112
- ```
113
- * @param {Array} arr The collection to iterate over.
114
- * @param {Function} fn The function invoked per iteration.
115
- * @returns {*} The matched element, else `undefined`.
116
- * @see {@link findRight}
117
- */
118
63
  export function find(arr, fn) {
64
+ const it = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
119
65
  if (Array.isArray(arr)) {
120
- if (isFunction(fn))
121
- return arr.find(fn);
122
- if (isNumber(fn) || isString(fn) || isSymbol(fn))
123
- return arr.find((x) => x?.[fn]);
124
- if (isObject(fn))
125
- return arr.find(matches(fn));
66
+ return arr.find(it);
126
67
  }
127
- }
128
- /**
129
- * This method is like {@link find} except that it iterates from right to left.
130
- * @example
131
- ```js
132
- findRight([1, 2, 3, 4], (n) => n % 2 === 1)
133
- // => 3
134
- ```
135
- * @param {Array} arr The collection to iterate over.
136
- * @param {Function} fn The function invoked per iteration.
137
- * @returns {*} The matched element, else `undefined`.
138
- * @see {@link find}
139
- */
140
- export function findRight(arr, fn) {
141
- if (Array.isArray(arr)) {
142
- for (let i = arr.length - 1; i >= 0; i--) {
143
- const x = arr[i];
144
- if (typeof fn === 'function') {
145
- if (fn(x))
146
- return x;
147
- }
148
- else if (typeof fn === 'string') {
149
- if (x?.[fn])
150
- return x;
151
- }
152
- else if (isObject(fn)) {
153
- if (matches(fn)(x))
154
- return x;
68
+ else if (isObject(arr)) {
69
+ for (const key of Object.keys(arr)) {
70
+ if (it(arr[key], key, arr)) {
71
+ return arr[key];
155
72
  }
156
73
  }
157
74
  }
@@ -167,7 +84,7 @@ export function findRight(arr, fn) {
167
84
  * @returns {Array<*>} The given array.
168
85
  */
169
86
  export function insert(arr, index, value) {
170
- if (!arr || arr.length <= index || index < 0)
87
+ if (!arr || index < 0)
171
88
  return arr;
172
89
  arr.splice(index, 0, value);
173
90
  return arr;
@@ -182,7 +99,7 @@ let objects = [
182
99
  ]
183
100
 
184
101
  filter(objects, matches({ a: 4, c: 6 }))
185
- // => [{ a: 4, b: 5, c: 6 }]
102
+ // [{ a: 4, b: 5, c: 6 }]
186
103
  ```
187
104
  * @param shape
188
105
  * @returns
@@ -201,48 +118,42 @@ export function forEach(collection, fn) {
201
118
  for (let i = 0; i < collection.length; i++) {
202
119
  const res = fn(collection[i], i, collection);
203
120
  if (res === false)
204
- return collection;
121
+ return;
205
122
  }
206
123
  }
207
124
  else if (isIterable(collection)) {
208
125
  for (const [index, value] of enumerate(collection)) {
209
126
  const res = fn(value, index, collection);
210
127
  if (res === false)
211
- return collection;
128
+ return;
212
129
  }
213
130
  }
214
131
  else {
215
132
  for (const key of keys(collection)) {
216
133
  const res = fn(collection[key], key, collection);
217
134
  if (res === false)
218
- return collection;
135
+ return;
219
136
  }
220
137
  }
221
138
  }
222
- /**
223
- * This method is like {@link forEach} except that it iterates over the collection from right to left.
224
-
225
- * @example
226
- ```js
227
- forEachRight([1, 2], (value) => {
228
- console.log(value)
229
- })
230
- // => Logs `2` then `1`.
231
- ```
232
- * @param {Array|Object} collection The collection to iterate over.
233
- * @param {Iteratee} fn The function invoked per iteration.
234
- * @returns {*} Returns `collection`.
235
- * @see {@link forEach}
236
- * @see {@link filter}
237
- * @see {@link map}
238
- */
139
+ export function findLast(arr, fn) {
140
+ let result;
141
+ const it = isFunction(fn) ? fn : matches(fn);
142
+ forEachRight(arr, (val, key) => {
143
+ if (it(val, key, arr)) {
144
+ result = val;
145
+ return false;
146
+ }
147
+ });
148
+ return result;
149
+ }
239
150
  export function forEachRight(collection, fn) {
240
151
  if (Array.isArray(collection)) {
241
152
  for (let i = collection.length - 1; i >= 0; i--) {
242
153
  const value = collection[i];
243
154
  const res = fn(value, i, collection);
244
155
  if (res === false)
245
- return collection;
156
+ return;
246
157
  }
247
158
  }
248
159
  else if (isObject(collection)) {
@@ -250,50 +161,12 @@ export function forEachRight(collection, fn) {
250
161
  for (let i = keys.length - 1; i >= 0; i--) {
251
162
  const key = keys[i];
252
163
  const value = collection[key];
253
- const res = fn(value, i, collection);
164
+ const res = fn(value, key, collection);
254
165
  if (res === false)
255
- return collection;
166
+ return;
256
167
  }
257
168
  }
258
- return collection;
259
- }
260
- /**
261
- * Flattens an array or object. Arrays will be flattened recursively up to `depth` times. Objects will be flattened recursively.
262
- * @example
263
- ```js
264
- flatten([1, [2, [3, [4]], 5]])
265
- // => [1, 2, [3, [4]], 5]
266
-
267
- flatten({
268
- dates: {
269
- expiry_date: '30 sep 2018',
270
- available: '30 sep 2017',
271
- min_contract_period: [
272
- {
273
- id: 1,
274
- name: '1 month'
275
- }
276
- ]
277
- },
278
- price: {
279
- currency: 'RM',
280
- value: 1500
281
- }
282
- })
283
- // => {
284
- 'dates.expiry_date': '30 sep 2018',
285
- 'dates.available': '30 sep 2017',
286
- 'dates.min_contract_period[0].id': 1,
287
- 'dates.min_contract_period[0].name': '1 month',
288
- 'price.currency': 'RM',
289
- 'price.value': 1500
290
169
  }
291
- ```
292
- * @param {Array|Object} arr The array or object to flatten.
293
- * @param {number} [depth=1] The max recursion depth.
294
- * @returns {*} The new flattened array or object.
295
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat Array.flat()}
296
- */
297
170
  export function flatten(arr, depth = 1) {
298
171
  if (!depth)
299
172
  return arr;
@@ -339,73 +212,20 @@ function flattenObj(obj, prefix = '', result = {}, keepNull = false) {
339
212
  }
340
213
  return result;
341
214
  }
342
- /**
343
- * Creates an array of values by running each element in collection thru iteratee. The iteratee is invoked with three arguments: `(value, index|key, collection)`.
344
- * @example
345
- ```js
346
- function square(n) {
347
- return n * n
348
- }
349
-
350
- map([4, 8], square)
351
- // => [16, 64]
352
-
353
- map({ a: 4, b: 8 }, square)
354
- // => [16, 64] (iteration order is not guaranteed)
355
-
356
- let users = [
357
- { user: 'barney' },
358
- { user: 'fred' }
359
- ]
360
-
361
- // The `property` iteratee shorthand.
362
- map(users, 'user')
363
- // => ['barney', 'fred']
364
- ```
365
- * @param {Array|Object} arr The collection to iterate over.
366
- * @param {Iteratee|PropertyKey} fn The function invoked per iteration.
367
- * @returns Returns the new mapped array.
368
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map Array.map()}
369
- */
370
215
  export function map(arr, fn) {
216
+ const it = isFunction(fn) ? fn : (obj) => get(fn, obj);
371
217
  if (Array.isArray(arr)) {
372
- return arr.map((x, i) => {
373
- if (typeof fn === 'function')
374
- return fn(x, i, arr);
375
- return x?.[fn];
376
- });
218
+ return arr.map((x, i) => it(x, i, arr));
377
219
  }
378
220
  if (isObject(arr)) {
379
- return Object.keys(arr).map((key) => {
380
- if (typeof fn === 'function')
381
- return fn(arr[key], key, arr);
382
- return get(fn, arr[key]);
383
- });
221
+ return Object.keys(arr).map((key) => it(arr[key], key, arr));
384
222
  }
385
223
  }
386
- /**
387
- * Creates an object composed of the picked object properties.
388
- * @param {Object} obj The source object.
389
- * @param {Iteratee|PropertyKey[]} paths The properties to pick. If `paths` is a function, it will be invoked per property with two values `(value, key)`.
390
- * @returns A new object with the properties.
391
- * @example
392
- ```js
393
- let object = { a: 1, b: '2', c: 3 }
394
-
395
- pick(object, ['a', 'c'])
396
- // => { a: 1, c: 3 }
397
-
398
- pick(object, (x) => isNumber(x))
399
- // => { a: 1, c: 3 }
400
- ```
401
- *
402
- * @see {@link omit}
403
- */
404
224
  export function pick(obj, paths) {
405
225
  if (!obj)
406
226
  return {};
407
227
  const result = {};
408
- if (typeof paths === 'function') {
228
+ if (isFunction(paths)) {
409
229
  for (const key of Object.keys(obj)) {
410
230
  if (paths(obj[key], key)) {
411
231
  result[key] = obj[key];
@@ -418,28 +238,11 @@ export function pick(obj, paths) {
418
238
  }
419
239
  return result;
420
240
  }
421
- /**
422
- * The opposite of {@link pick} - this method creates an object composed of the own and inherited enumerable property paths of `object` that are not omitted.
423
- * @example
424
- ```js
425
- let object = { 'a': 1, 'b': '2', 'c': 3 }
426
-
427
- omit(object, ['a', 'c'])
428
- // => { 'b': '2' }
429
-
430
- omit(object, (x) => isNumber(x))
431
- // => { 'b': '2' }
432
- ```
433
- * @param {Object} obj The source object.
434
- * @param {Iteratee|PropertyKey[]} paths The property paths to omit.
435
- * @returns {Object} Returns the new object.
436
- * @see {@link pick}
437
- */
438
241
  export function omit(obj, paths) {
439
242
  if (!obj)
440
243
  return {};
441
244
  const result = {};
442
- if (typeof paths === 'function') {
245
+ if (isFunction(paths)) {
443
246
  for (const key of Object.keys(obj)) {
444
247
  if (!paths(obj[key], key)) {
445
248
  result[key] = obj[key];
@@ -453,61 +256,24 @@ export function omit(obj, paths) {
453
256
  }
454
257
  return result;
455
258
  }
456
- /**
457
- * This method is like {@link find} except that it returns the index of the first element `predicate` returns truthy for instead of the element itself.
458
- * @param {Array} obj The array to inspect.
459
- * @param {string|Object|Iteratee} fn The predicate function
460
- * @param {number} [start=0] The index to search from.
461
- * @returns {number} The index of the found value, else -1
462
- * @example
463
- ```js
464
- let users = [
465
- { 'user': 'barney', 'active': false },
466
- { 'user': 'fred', 'active': false },
467
- { 'user': 'pebbles', 'active': true }
468
- ]
469
-
470
- index(users, (o) => o.user == 'barney')
471
- // => 0
472
-
473
- // The `shape` iteratee shorthand.
474
- index(users, { 'user': 'fred', 'active': false })
475
- // => 1
476
-
477
- // The `property` iteratee shorthand.
478
- index(users, 'active')
479
- // => 2
480
- ```
481
- * @see {@link indexOf}
482
- * @see {@link lastIndex}
483
- *
484
- */
485
- export function index(obj, fn, start = 0) {
486
- if (obj == null)
487
- return;
259
+ export function findIndex(obj, fn, start = 0) {
260
+ if (!obj)
261
+ return -1;
488
262
  const length = obj.length;
489
263
  if (length && start < 0) {
490
264
  start = Math.max(start + length, 0);
491
265
  }
492
266
  if (!length || start >= length)
493
267
  return -1;
494
- if (isObject(fn)) {
495
- fn = matches(fn);
496
- }
268
+ const it = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
497
269
  for (; start < length; start++) {
498
- if (typeof fn === 'function') {
499
- if (fn(obj[start], start, obj))
500
- return start;
501
- }
502
- else {
503
- if (obj[start]?.[fn])
504
- return start;
505
- }
270
+ if (it(obj[start], start, obj))
271
+ return start;
506
272
  }
507
273
  return -1;
508
274
  }
509
275
  /**
510
- * This method is like {@link index} except that it searches for a given value directly, instead of using a predicate function.
276
+ * This method is like {@link findIndex} except that it searches for a given value directly, instead of using a predicate function.
511
277
  * @param {Array} obj The array to inspect.
512
278
  * @param {*} value The value to find
513
279
  * @param {number} [start=0] The index to search from.
@@ -515,18 +281,18 @@ export function index(obj, fn, start = 0) {
515
281
  * @example
516
282
  ```js
517
283
  indexOf([1, 2, 1, 2], 2)
518
- // => 1
284
+ // 1
519
285
 
520
286
  // Search from a `start` index.
521
287
  indexOf([1, 2, 1, 2], 2, 2)
522
- // => 3
288
+ // 3
523
289
  ```
524
- * @see {@link index}
290
+ * @see {@link findIndex}
525
291
  * @see {@link lastIndexOf}
526
292
  */
527
293
  export function indexOf(obj, value, start = 0) {
528
- if (obj == null)
529
- return;
294
+ if (!obj)
295
+ return -1;
530
296
  const op = call(obj, 'indexOf', value, start);
531
297
  if (op != null)
532
298
  return op;
@@ -542,54 +308,18 @@ export function indexOf(obj, value, start = 0) {
542
308
  }
543
309
  return -1;
544
310
  }
545
- /**
546
- * This method is like {@link index} except that it iterates the collection from right to left.
547
- * @param {Array} obj The array to inspect.
548
- * @param {string|Iteratee|Object} fn The function invoked per iteration.
549
- * @param {number} [start] The index to search from.
550
- * @returns {number} The index of the found value, else -1
551
- * @example
552
- ```js
553
- let users = [
554
- { 'user': 'barney', 'active': true },
555
- { 'user': 'fred', 'active': false },
556
- { 'user': 'pebbles', 'active': false }
557
- ]
558
-
559
- findLastIndex(users, (o) => o.user == 'pebbles')
560
- // => 2
561
-
562
- // The `shape` iteratee shorthand.
563
- findLastIndex(users, { 'user': 'barney', 'active': true })
564
- // => 0
565
-
566
- // The `property` iteratee shorthand.
567
- findLastIndex(users, 'active')
568
- // => 0
569
- ```
570
- * @see {@link index}
571
- * @see {@link lastIndexOf}
572
- */
573
- export function lastIndex(obj, fn, start) {
574
- if (obj == null)
575
- return;
576
- const length = obj.length;
311
+ export function findLastIndex(arr, fn, start) {
312
+ if (arr == null)
313
+ return -1;
314
+ const length = arr.length;
577
315
  if (start == null)
578
316
  start = length - 1;
579
317
  if (!length || start < 0)
580
318
  return -1;
581
- if (isObject(fn)) {
582
- fn = matches(fn);
583
- }
319
+ const it = isFunction(fn) ? fn : isObject(fn) ? matches(fn) : (obj) => get(fn, obj);
584
320
  for (; start >= 0; start--) {
585
- if (typeof fn === 'function') {
586
- if (fn(obj[start]))
587
- return start;
588
- }
589
- else {
590
- if (obj[start]?.[fn])
591
- return start;
592
- }
321
+ if (it(arr[start], start, arr))
322
+ return start;
593
323
  }
594
324
  return -1;
595
325
  }
@@ -602,18 +332,18 @@ export function lastIndex(obj, fn, start) {
602
332
  * @example
603
333
  ```js
604
334
  lastIndexOf([1, 2, 1, 2], 2)
605
- // => 3
335
+ // 3
606
336
 
607
337
  // Search from the `fromIndex`.
608
338
  lastIndexOf([1, 2, 1, 2], 2, 2)
609
- // => 1
339
+ // 1
610
340
  ```
611
- * @see {@link lastIndex}
341
+ * @see {@link findLastIndex}
612
342
  * @see {@link indexOf}
613
343
  */
614
344
  export function lastIndexOf(obj, value, start) {
615
345
  if (obj == null)
616
- return;
346
+ return -1;
617
347
  const op = call(obj, 'lastIndexOf', value, start);
618
348
  if (op != null)
619
349
  return op;
@@ -628,14 +358,6 @@ export function lastIndexOf(obj, value, start) {
628
358
  }
629
359
  return -1;
630
360
  }
631
- /**
632
- * Creates a shallow clone of `value`. If `deep` is `true` it will clone it recursively.
633
- * @param {*} value
634
- * @param {boolean} [deep=false]
635
- * @return The clone value
636
- * @see {@link cloneArray}
637
- * @see {@link cloneTypedArray}
638
- */
639
361
  export function clone(value, deep = false) {
640
362
  if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
641
363
  return cloneTypedArray(value, deep);
@@ -679,46 +401,18 @@ export function cloneArray(arr, deep = false) {
679
401
  * @returns The new array
680
402
  * @see {@link clone}
681
403
  */
682
- export function cloneTypedArray(typedArray, isDeep) {
404
+ export function cloneTypedArray(typedArray, isDeep = false) {
683
405
  const buffer = isDeep ? structuredClone(typedArray) : typedArray.buffer;
684
406
  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
685
407
  }
686
- /**
687
- * Creates a duplicate-free version of an array, using a `Set` for equality comparisons, in which only the first occurrence of each element is kept. The order of result values is not guaranteed.
688
- * @param arr The array containing duplicated elements
689
- * @param fn The iteratee invoked per element.
690
- * @returns Returns the new duplicate free array.
691
- * @example
692
- ```js
693
- uniq([2, 1, 2])
694
- // => [2, 1]
695
-
696
- uniq([2.1, 1.2, 2.3], Math.floor)
697
- // => [2.1, 1.2]
698
- ```
699
- *
700
- * @see {@link sortedUniq}
701
- */
702
408
  export function uniq(arr, fn = id) {
703
409
  const keys = new Set();
704
- const mapper = typeof fn === 'function' ? fn : (x) => x?.[fn];
410
+ const it = isFunction(fn) ? fn : (x) => get(fn, x);
705
411
  for (const x of arr) {
706
- keys.add(mapper(x));
412
+ keys.add(it(x));
707
413
  }
708
414
  return Array.from(keys.values());
709
415
  }
710
- /**
711
- * This method is like {@link uniq} except that it sorts the results in ascending order
712
- * @param arr The array containing duplicated elements
713
- * @param fn The iteratee invoked per element.
714
- * @returns Returns the new duplicate free array
715
- * @example
716
- ```js
717
- uniq([2, 1, 2])
718
- // => [1, 2]
719
- ```
720
- * @see {@link uniq}
721
- */
722
416
  export function sortedUniq(arr, fn = id) {
723
417
  const values = uniq(arr, fn);
724
418
  values.sort(compare);
@@ -804,7 +498,7 @@ let other = {
804
498
  }
805
499
 
806
500
  merge(object, other)
807
- // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
501
+ // { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
808
502
  ```
809
503
  */
810
504
  export function merge(object, ...sources) {
@@ -823,7 +517,7 @@ export function merge(object, ...sources) {
823
517
  * @example
824
518
  ```js
825
519
  defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 })
826
- // => { 'a': 1, 'b': 2 }
520
+ // { 'a': 1, 'b': 2 }
827
521
  ```
828
522
  */
829
523
  export function defaults(object, ...sources) {
@@ -842,7 +536,7 @@ export function defaults(object, ...sources) {
842
536
  * @example
843
537
  ```js
844
538
  [...difference([2, 1], [2, 3])]
845
- // => [1]
539
+ // [1]
846
540
  ```
847
541
  * @see {@link union}
848
542
  * @see {@link intersection}
@@ -866,7 +560,7 @@ export function* difference(...args) {
866
560
  * @example
867
561
  ```js
868
562
  [...intersection([2, 1], [2, 3])]
869
- // => [2]
563
+ // [2]
870
564
  ```
871
565
  * @see {@link difference}
872
566
  * @see {@link union}
@@ -893,7 +587,7 @@ export function* intersection(...args) {
893
587
  * @example
894
588
  ```js
895
589
  [...union([2], [1, 2])]
896
- // => [2, 1]
590
+ // [2, 1]
897
591
  ```
898
592
  * @see {@link difference}
899
593
  * @see {@link intersection}
@@ -909,26 +603,9 @@ export function* union(...args) {
909
603
  yield item;
910
604
  }
911
605
  }
912
- /**
913
- * Creates an object composed of keys generated from the results of running each element of `arr` thru `func`. The order of grouped values is determined by the order they occur in `arr`. The corresponding value of each key is an array of elements responsible for generating the key.
914
- *
915
- * @param arr The collection to iterate over.
916
- * @param [func=id] The iteratee to transform keys.
917
- * @returns Returns the aggregated object.
918
- *
919
- * @example
920
- ```js
921
- groupBy([6.1, 4.2, 6.3], Math.floor)
922
- // => { '4': [4.2], '6': [6.1, 6.3] }
923
-
924
- // The `property` iteratee shorthand.
925
- groupBy(['one', 'two', 'three'], 'length')
926
- // => { '3': ['one', 'two'], '5': ['three'] }
927
- ```
928
- */
929
606
  export function groupBy(arr, func = id) {
607
+ const useKey = isFunction(func) ? func : (obj) => get(func, obj);
930
608
  const results = {};
931
- const useKey = typeof func === 'function' ? func : partial(get, func);
932
609
  forEach(arr, (value) => {
933
610
  const groupKey = useKey(value);
934
611
  const values = results[groupKey] || [];
@@ -937,27 +614,9 @@ export function groupBy(arr, func = id) {
937
614
  });
938
615
  return results;
939
616
  }
940
- /**
941
- * Similar to {@link groupBy} but it returns a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map Map} object with the results.
942
- *
943
- * @param arr The collection to iterate over.
944
- * @param {Function | PropertyKey} [func=id] The iteratee to transform keys.
945
- * @returns {Map} Returns the aggregated map object.
946
- * @template K, V
947
- *
948
- * @example
949
- ```js
950
- groupByMap([6.1, 4.2, 6.3], Math.floor)
951
- // => Map { 4: [4.2], 6: [6.1, 6.3] }
952
-
953
- // The `property` iteratee shorthand.
954
- groupByMap(['one', 'two', 'three'], 'length')
955
- // => Map { 3: ['one', 'two'], 5: ['three'] }
956
- ```
957
- */
958
617
  export function groupByMap(arr, func = id) {
959
618
  const results = new Map();
960
- const useKey = typeof func === 'function' ? func : partial(get, func);
619
+ const useKey = isFunction(func) ? func : (obj) => get(func, obj);
961
620
  forEach(arr, (value) => {
962
621
  const groupKey = useKey(value);
963
622
  const values = results.get(groupKey) || [];
@@ -966,20 +625,104 @@ export function groupByMap(arr, func = id) {
966
625
  });
967
626
  return results;
968
627
  }
628
+ export function remove(arr, func) {
629
+ const it = isFunction(func) ? func : isArray(func) ? (x) => func.includes(x) : (x) => func === x;
630
+ return arr.filter((x, i) => !it(x, i, arr));
631
+ }
969
632
  /**
970
- * Removes all elements from array that `func` returns truthy for and returns an array of the removed elements.
971
- * @param arr The array to remove from.
972
- * @param func The function invoked per iteration or value(s) or value to remove.
973
- * @returns
633
+ * Returns the index of `x` in a **sorted** array if found, in `O(log n)` using binary search.
634
+ * If the element is not found, returns a negative integer.
635
+ * @param arr The array to sort
636
+ * @param x The element to find
637
+ * @param lo The starting index
638
+ * @param hi The end index to search within
639
+ * @param comp The compare function to check for `x`
640
+ * @returns {number} The index if the element is found or a negative integer.
974
641
  */
975
- export function remove(arr, func) {
976
- return arr.filter((x, i) => {
977
- if (isArray(func))
978
- return !func.includes(x);
979
- else if (isFunction(func))
980
- return !func(x, i, arr);
981
- return x !== func;
982
- });
642
+ export function binarySearch(arr, x, lo = 0, hi, comp = compare) {
643
+ hi = hi ?? arr.length - 1;
644
+ while (lo < hi) {
645
+ const mid = (lo + hi) >> 1;
646
+ const check = comp(x, arr[mid]);
647
+ if (check === 0)
648
+ return mid;
649
+ if (check > 0)
650
+ lo = mid + 1;
651
+ else
652
+ hi = mid - 1;
653
+ }
654
+ if (comp(x, arr[lo]) === 0)
655
+ return lo;
656
+ // Returns (-lo - 1) where n is the insertion point for new element in the range
657
+ return -lo - 1;
658
+ }
659
+ /**
660
+ * Returns an insertion index which comes after any existing entries of `x` in a **sorted** array, using binary search.
661
+ * @param arr The array to sort
662
+ * @param x The element to find
663
+ * @param lo The starting index
664
+ * @param hi The end index to search within
665
+ * @param comp The compare function to check for `x`
666
+ * @returns {number}
667
+ */
668
+ export function bisect(arr, x, lo = 0, hi, comp = compare) {
669
+ hi = hi ?? arr.length;
670
+ while (lo < hi) {
671
+ const mid = (lo + hi) >> 1;
672
+ const check = comp(x, arr[mid]);
673
+ if (check >= 0)
674
+ lo = mid + 1;
675
+ else
676
+ hi = mid - 1;
677
+ }
678
+ return lo;
679
+ }
680
+ /**
681
+ * Returns an insertion index which comes before any existing entries of `x` in a **sorted** array, using binary search.
682
+ * @param arr The array to sort
683
+ * @param x The element to find
684
+ * @param lo The starting index
685
+ * @param hi The end index to search within
686
+ * @param comp The compare function to check for `x`
687
+ * @returns {number}
688
+ */
689
+ export function bisectLeft(arr, x, lo = 0, hi, comp = compare) {
690
+ hi = hi ?? arr.length;
691
+ while (lo < hi) {
692
+ const mid = (lo + hi) >> 1;
693
+ const check = comp(x, arr[mid]);
694
+ if (check <= 0)
695
+ hi = mid - 1;
696
+ else
697
+ lo = mid + 1;
698
+ }
699
+ return lo;
700
+ }
701
+ /**
702
+ * Runs {@link bisect} first to locate an insertion point, and inserts the value `x` in the sorted array after any existing entries of `x` to maintain sort order.
703
+ * Please note this method is `O(n)` because insertion resizes the array.
704
+ * @param arr The array to insert into
705
+ * @param x The element to insert
706
+ * @param lo The starting index
707
+ * @param hi The end index to search within
708
+ * @param comp The compare function to check for `x`
709
+ * @returns {Array}
710
+ */
711
+ export function insort(arr, x, lo = 0, hi, comp = compare) {
712
+ const index = bisect(arr, x, lo, hi, comp);
713
+ return insert(arr, index, x);
714
+ }
715
+ /**
716
+ * Runs {@link bisectLeft} first to locate an insertion point, and inserts the value `x` in the sorted array before any existing entries of `x` to maintain sort order.
717
+ * Please note this method is `O(n)` because insertion resizes the array.
718
+ * @param arr The array to insert into
719
+ * @param x The element to insert
720
+ * @param lo The starting index
721
+ * @param hi The end index to search within
722
+ * @param comp The compare function to check for `x`
723
+ * @returns {Array}
724
+ */
725
+ export function insortLeft(arr, x, lo = 0, hi, comp = compare) {
726
+ const index = bisectLeft(arr, x, lo, hi, comp);
727
+ return insert(arr, index, x);
983
728
  }
984
- // TODO: binary search utils
985
- // TODO: Counter