@tim-code/my-util 0.4.1 → 0.4.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tim-code/my-util",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "author": "Tim Sprowl",
package/src/find.js CHANGED
@@ -268,3 +268,72 @@ export function findMax(array, { key, cutoff = -Infinity } = {}) {
268
268
  }
269
269
  return closest
270
270
  }
271
+
272
+ /**
273
+ * Like Array.prototype.findIndex but starts from given index.
274
+ * @template T
275
+ * @param {Array<T>} array
276
+ * @param {number} fromIndex
277
+ * @param {(value: T, index: number, array: Array<T>) => boolean} callback
278
+ * @returns {number}
279
+ */
280
+ export function findIndexFrom(array, fromIndex, callback) {
281
+ for (let i = fromIndex; i < array.length; i++) {
282
+ if (callback(array[i], i, array)) {
283
+ return i
284
+ }
285
+ }
286
+ return -1
287
+ }
288
+
289
+ /**
290
+ * Like Array.prototype.find but starts from given index.
291
+ * @template T
292
+ * @param {Array<T>} array
293
+ * @param {number} fromIndex
294
+ * @param {(value: T, index: number, array: Array<T>) => boolean} callback
295
+ * @returns {T|undefined}
296
+ */
297
+ export function findFrom(array, fromIndex, callback) {
298
+ const foundIndex = findIndexFrom(array, fromIndex, callback)
299
+ if (foundIndex < 0) {
300
+ return undefined
301
+ }
302
+ return array[foundIndex]
303
+ }
304
+
305
+ /**
306
+ * Like Array.prototype.findLastIndex but starts from given index.
307
+ * @template T
308
+ * @param {Array<T>} array
309
+ * @param {number} fromIndex If greater or equal to length, coerces to last index in array.
310
+ * @param {(value: T, index: number, array: Array<T>) => boolean} callback
311
+ * @returns {number}
312
+ */
313
+ export function findLastIndexFrom(array, fromIndex, callback) {
314
+ if (fromIndex >= array.length) {
315
+ fromIndex = array.length - 1
316
+ }
317
+ for (let i = fromIndex; i >= 0; i--) {
318
+ if (callback(array[i], i, array)) {
319
+ return i
320
+ }
321
+ }
322
+ return -1
323
+ }
324
+
325
+ /**
326
+ * Like Array.prototype.findLast but starts from given index.
327
+ * @template T
328
+ * @param {Array<T>} array
329
+ * @param {number} fromIndex
330
+ * @param {(value: T, index: number, array: Array<T>) => boolean} callback
331
+ * @returns {T|undefined}
332
+ */
333
+ export function findLastFrom(array, fromIndex, callback) {
334
+ const foundIndex = findLastIndexFrom(array, fromIndex, callback)
335
+ if (foundIndex < 0) {
336
+ return undefined
337
+ }
338
+ return array[foundIndex]
339
+ }
package/src/find.test.js CHANGED
@@ -9,6 +9,10 @@ const {
9
9
  findClosest,
10
10
  findMin,
11
11
  findMax,
12
+ findIndexFrom,
13
+ findFrom,
14
+ findLastIndexFrom,
15
+ findLastFrom,
12
16
  } = await import("./find.js")
13
17
 
14
18
  describe("findClosestAbs", () => {
@@ -284,3 +288,117 @@ describe("findMax", () => {
284
288
  expect(findMax([3, 1, 4, 2], { cutoff: 4 })).toBeUndefined()
285
289
  })
286
290
  })
291
+
292
+ describe("findIndexFrom", () => {
293
+ it("returns the index of the first matching element from fromIndex", () => {
294
+ expect(findIndexFrom([1, 2, 3, 4], 1, (x) => x > 2)).toBe(2)
295
+ expect(findIndexFrom([1, 2, 3, 4], 2, (x) => x > 2)).toBe(2)
296
+ expect(findIndexFrom([1, 2, 3, 4], 3, (x) => x > 2)).toBe(3)
297
+ })
298
+
299
+ it("returns -1 if no element matches", () => {
300
+ expect(findIndexFrom([1, 2, 3, 4], 2, (x) => x > 10)).toBe(-1)
301
+ })
302
+
303
+ it("returns -1 for empty array", () => {
304
+ expect(findIndexFrom([], 0, () => true)).toBe(-1)
305
+ })
306
+
307
+ it("passes correct arguments to callback", () => {
308
+ const arr = [10, 20, 30]
309
+ const called = []
310
+ findIndexFrom(arr, 1, (value, index, array) => {
311
+ called.push([value, index, array])
312
+ return false
313
+ })
314
+ expect(called[0][0]).toBe(20)
315
+ expect(called[0][1]).toBe(1)
316
+ expect(called[0][2]).toBe(arr)
317
+ })
318
+ })
319
+
320
+ describe("findFrom", () => {
321
+ it("returns the first matching element from fromIndex", () => {
322
+ expect(findFrom([1, 2, 3, 4], 1, (x) => x > 2)).toBe(3)
323
+ expect(findFrom([1, 2, 3, 4], 2, (x) => x > 2)).toBe(3)
324
+ expect(findFrom([1, 2, 3, 4], 3, (x) => x > 2)).toBe(4)
325
+ })
326
+
327
+ it("returns undefined if no element matches", () => {
328
+ expect(findFrom([1, 2, 3, 4], 2, (x) => x > 10)).toBeUndefined()
329
+ })
330
+
331
+ it("returns undefined for empty array", () => {
332
+ expect(findFrom([], 0, () => true)).toBeUndefined()
333
+ })
334
+
335
+ it("passes correct arguments to callback", () => {
336
+ const arr = [10, 20, 30]
337
+ const called = []
338
+ findFrom(arr, 1, (value, index, array) => {
339
+ called.push([value, index, array])
340
+ return false
341
+ })
342
+ expect(called[0][0]).toBe(20)
343
+ expect(called[0][1]).toBe(1)
344
+ expect(called[0][2]).toBe(arr)
345
+ })
346
+ })
347
+
348
+ describe("findLastIndexFrom", () => {
349
+ it("returns the index of the last matching element from fromIndex (backwards)", () => {
350
+ expect(findLastIndexFrom([1, 2, 3, 4], 2, (x) => x < 3)).toBe(1)
351
+ expect(findLastIndexFrom([1, 2, 3, 4], 3, (x) => x < 3)).toBe(1)
352
+ expect(findLastIndexFrom([1, 2, 3, 4], 1, (x) => x < 3)).toBe(1)
353
+ expect(findLastIndexFrom([1, 2, 3, 4], 0, (x) => x < 3)).toBe(0)
354
+ })
355
+
356
+ it("returns -1 if no element matches", () => {
357
+ expect(findLastIndexFrom([1, 2, 3, 4], 3, (x) => x > 10)).toBe(-1)
358
+ })
359
+
360
+ it("returns -1 for empty array", () => {
361
+ expect(findLastIndexFrom([], 0, () => true)).toBe(-1)
362
+ })
363
+
364
+ it("passes correct arguments to callback", () => {
365
+ const arr = [10, 20, 30]
366
+ const called = []
367
+ findLastIndexFrom(arr, 2, (value, index, array) => {
368
+ called.push([value, index, array])
369
+ return false
370
+ })
371
+ expect(called[0][0]).toBe(30)
372
+ expect(called[0][1]).toBe(2)
373
+ expect(called[0][2]).toBe(arr)
374
+ })
375
+ })
376
+
377
+ describe("findLastFrom", () => {
378
+ it("returns the last matching element from fromIndex (backwards)", () => {
379
+ expect(findLastFrom([1, 2, 3, 4], 2, (x) => x < 3)).toBe(2)
380
+ expect(findLastFrom([1, 2, 3, 4], 3, (x) => x < 3)).toBe(2)
381
+ expect(findLastFrom([1, 2, 3, 4], 1, (x) => x < 3)).toBe(2)
382
+ expect(findLastFrom([1, 2, 3, 4], 0, (x) => x < 3)).toBe(1)
383
+ })
384
+
385
+ it("returns undefined if no element matches", () => {
386
+ expect(findLastFrom([1, 2, 3, 4], 3, (x) => x > 10)).toBeUndefined()
387
+ })
388
+
389
+ it("returns undefined for empty array", () => {
390
+ expect(findLastFrom([], 0, () => true)).toBeUndefined()
391
+ })
392
+
393
+ it("passes correct arguments to callback", () => {
394
+ const arr = [10, 20, 30]
395
+ const called = []
396
+ findLastFrom(arr, 2, (value, index, array) => {
397
+ called.push([value, index, array])
398
+ return false
399
+ })
400
+ expect(called[0][0]).toBe(30)
401
+ expect(called[0][1]).toBe(2)
402
+ expect(called[0][2]).toBe(arr)
403
+ })
404
+ })