@tim-code/my-util 0.4.8 → 0.4.9
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 +1 -1
- package/src/find.js +61 -17
- package/src/find.test.js +112 -0
package/package.json
CHANGED
package/src/find.js
CHANGED
|
@@ -271,39 +271,83 @@ export function findMax(array, { key, cutoff = -Infinity } = {}) {
|
|
|
271
271
|
|
|
272
272
|
/**
|
|
273
273
|
* Find the first truthy value in an array.
|
|
274
|
-
* Supports "from" and "to" being reversed to "find last truthy".
|
|
274
|
+
* Supports "from" and "to"/"until" being reversed to "find last truthy" if "reverse" is true.
|
|
275
275
|
* @template T
|
|
276
276
|
* @param {Array<T>} array
|
|
277
277
|
* @param {Object} $1
|
|
278
278
|
* @param {string|Function=} $1.key Specifies an alternative to using each element as the value.
|
|
279
279
|
* If string, then accesses each element at that key to get value.
|
|
280
280
|
* If function, then calls the callback on each element to get value.
|
|
281
|
-
* @param {number=} $1.from Numeric index to start from: inclusive, defaults to 0
|
|
281
|
+
* @param {number=} $1.from Numeric index to start from: inclusive, defaults to `0`
|
|
282
282
|
* @param {number=} $1.until Numeric index to end at: exclusive, defaults to `array.length`
|
|
283
|
+
* @param {number=} $1.to Numeric index to end at: inclusive, defaults to `array.length - 1`; takes precedence over "until"
|
|
284
|
+
* @param {boolean=} $1.reverse If true, looks through the array in reverse. Default is false.
|
|
285
|
+
* When true, findTruthy() will still start from "from" and end at "to"/"until".
|
|
286
|
+
* When true, changes the default values of "from", "until", "to" to `array.length - 1`, `-1`, `0`.
|
|
283
287
|
* @returns {T}
|
|
284
288
|
*/
|
|
285
|
-
|
|
289
|
+
// eslint-disable-next-line complexity
|
|
290
|
+
export function findTruthy(
|
|
291
|
+
array,
|
|
292
|
+
{
|
|
293
|
+
key,
|
|
294
|
+
reverse = false,
|
|
295
|
+
from = reverse ? array.length - 1 : 0,
|
|
296
|
+
until = reverse ? -1 : array.length,
|
|
297
|
+
to = reverse ? until + 1 : until - 1,
|
|
298
|
+
} = {}
|
|
299
|
+
) {
|
|
286
300
|
if (typeof key === "function") {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
301
|
+
if (reverse) {
|
|
302
|
+
for (let i = from; i >= to; i--) {
|
|
303
|
+
const element = array[i]
|
|
304
|
+
const value = key(element, i, array)
|
|
305
|
+
if (value) {
|
|
306
|
+
return element
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
for (let i = from; i <= to; i++) {
|
|
311
|
+
const element = array[i]
|
|
312
|
+
const value = key(element, i, array)
|
|
313
|
+
if (value) {
|
|
314
|
+
return element
|
|
315
|
+
}
|
|
292
316
|
}
|
|
293
317
|
}
|
|
294
318
|
} else if (typeof key === "number" || typeof key === "string") {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
319
|
+
if (reverse) {
|
|
320
|
+
for (let i = from; i >= to; i--) {
|
|
321
|
+
const element = array[i]
|
|
322
|
+
const value = element[key]
|
|
323
|
+
if (value) {
|
|
324
|
+
return element
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
for (let i = from; i <= to; i++) {
|
|
329
|
+
const element = array[i]
|
|
330
|
+
const value = element[key]
|
|
331
|
+
if (value) {
|
|
332
|
+
return element
|
|
333
|
+
}
|
|
300
334
|
}
|
|
301
335
|
}
|
|
302
336
|
} else {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
337
|
+
// eslint-disable-next-line no-lonely-if
|
|
338
|
+
if (reverse) {
|
|
339
|
+
for (let i = from; i >= to; i--) {
|
|
340
|
+
const value = array[i]
|
|
341
|
+
if (value) {
|
|
342
|
+
return value
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
for (let i = from; i <= to; i++) {
|
|
347
|
+
const value = array[i]
|
|
348
|
+
if (value) {
|
|
349
|
+
return value
|
|
350
|
+
}
|
|
307
351
|
}
|
|
308
352
|
}
|
|
309
353
|
}
|
package/src/find.test.js
CHANGED
|
@@ -323,4 +323,116 @@ describe("findTruthy", () => {
|
|
|
323
323
|
expect(findTruthy([0, 1, 2], { from: 2, until: 2 })).toBeUndefined()
|
|
324
324
|
expect(findTruthy([0, 1, 2], { from: 3, until: 2 })).toBeUndefined()
|
|
325
325
|
})
|
|
326
|
+
|
|
327
|
+
it("respects the new 'to' option (inclusive end)", () => {
|
|
328
|
+
const arr = [0, 1, 2, 3]
|
|
329
|
+
expect(findTruthy(arr, { from: 1, to: 2 })).toBe(1)
|
|
330
|
+
expect(findTruthy(arr, { from: 2, to: 3 })).toBe(2)
|
|
331
|
+
expect(findTruthy(arr, { from: 2, to: 2 })).toBe(2)
|
|
332
|
+
expect(findTruthy(arr, { from: 2, to: 1 })).toBeUndefined()
|
|
333
|
+
expect(findTruthy(arr, { from: 0, to: 0 })).toBeUndefined()
|
|
334
|
+
expect(findTruthy(arr, { from: 1, to: 1 })).toBe(1)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it("prefers 'to' over 'until' if both are given", () => {
|
|
338
|
+
const arr = [0, 1, 2, 3]
|
|
339
|
+
// 'to' = 1, so only index 1 is checked, even though until=4
|
|
340
|
+
expect(findTruthy(arr, { from: 1, until: 4, to: 1 })).toBe(1)
|
|
341
|
+
// 'to' = 2, so indices 1 and 2 checked, even though until=2 (which would skip 2)
|
|
342
|
+
expect(findTruthy(arr, { from: 1, until: 2, to: 2 })).toBe(1)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it("works with key as function and 'to'", () => {
|
|
346
|
+
const arr = [{ v: 0 }, { v: 0 }, { v: 2 }, { v: 3 }]
|
|
347
|
+
expect(findTruthy(arr, { key: (e) => e.v, from: 1, to: 2 })).toEqual({ v: 2 })
|
|
348
|
+
expect(findTruthy(arr, { key: (e) => e.v, from: 1, to: 1 })).toBeUndefined()
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it("works with key as string and 'to'", () => {
|
|
352
|
+
const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
|
|
353
|
+
expect(findTruthy(arr, { key: "x", from: 0, to: 1 })).toEqual({ x: 2 })
|
|
354
|
+
expect(findTruthy(arr, { key: "x", from: 1, to: 1 })).toEqual({ x: 2 })
|
|
355
|
+
expect(findTruthy(arr, { key: "x", from: 2, to: 1 })).toBeUndefined()
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
it("works with key as number and 'to'", () => {
|
|
359
|
+
const arr = [[0], [2], [0]]
|
|
360
|
+
expect(findTruthy(arr, { key: 0, from: 0, to: 1 })).toEqual([2])
|
|
361
|
+
expect(findTruthy(arr, { key: 0, from: 1, to: 1 })).toEqual([2])
|
|
362
|
+
expect(findTruthy(arr, { key: 0, from: 2, to: 1 })).toBeUndefined()
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
// New tests for reverse mode and its interaction with from, to, until
|
|
366
|
+
it("finds last truthy value with reverse=true and default from/to", () => {
|
|
367
|
+
const arr = [0, 1, 2, 3, 0]
|
|
368
|
+
expect(findTruthy(arr, { reverse: true })).toBe(3)
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it("finds last truthy value with reverse=true and custom from/to", () => {
|
|
372
|
+
const arr = [0, 1, 2, 3, 4]
|
|
373
|
+
// from=3, to=1 (reverse), should check indices 3,2,1
|
|
374
|
+
expect(findTruthy(arr, { reverse: true, from: 3, to: 1 })).toBe(3)
|
|
375
|
+
// from=4, to=2, should check 4,3,2
|
|
376
|
+
expect(findTruthy(arr, { reverse: true, from: 4, to: 2 })).toBe(4)
|
|
377
|
+
// from=2, to=0, should check 2,1,0
|
|
378
|
+
expect(findTruthy(arr, { reverse: true, from: 2, to: 0 })).toBe(2)
|
|
379
|
+
// from=2, to=2, should check only 2
|
|
380
|
+
expect(findTruthy(arr, { reverse: true, from: 2, to: 2 })).toBe(2)
|
|
381
|
+
// from=2, to=3, should check 2,1,0 (since to > from, loop doesn't run)
|
|
382
|
+
expect(findTruthy(arr, { reverse: true, from: 2, to: 3 })).toBeUndefined()
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it("finds last truthy value with reverse=true and until", () => {
|
|
386
|
+
const arr = [0, 1, 2, 3, 0]
|
|
387
|
+
// until=1, so to=until+1=2, from=4, should check 4,3,2
|
|
388
|
+
expect(findTruthy(arr, { reverse: true, until: 1 })).toBe(3)
|
|
389
|
+
expect(findTruthy(arr, { reverse: true, until: 2 })).toBe(3)
|
|
390
|
+
expect(findTruthy(arr, { reverse: true, until: 3 })).toBe(undefined)
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it("finds last truthy value with reverse=true and key as function", () => {
|
|
394
|
+
const arr = [{ v: 0 }, { v: 2 }, { v: 0 }]
|
|
395
|
+
expect(findTruthy(arr, { key: (e) => e.v, reverse: true })).toEqual({ v: 2 })
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it("finds last truthy value with reverse=true and key as string", () => {
|
|
399
|
+
const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
|
|
400
|
+
expect(findTruthy(arr, { key: "x", reverse: true })).toEqual({ x: 2 })
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it("finds last truthy value with reverse=true and key as number", () => {
|
|
404
|
+
const arr = [[0], [2], [0]]
|
|
405
|
+
expect(findTruthy(arr, { key: 0, reverse: true })).toEqual([2])
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it("returns undefined if no truthy value in reverse mode", () => {
|
|
409
|
+
expect(findTruthy([0, 0, 0], { reverse: true })).toBeUndefined()
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it("returns undefined if reverse=true and from < to", () => {
|
|
413
|
+
expect(findTruthy([0, 1, 2], { reverse: true, from: 0, to: 2 })).toBeUndefined()
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
it("reverse=true with custom from/to and key as function", () => {
|
|
417
|
+
const arr = [{ v: 0 }, { v: 2 }, { v: 0 }, { v: 3 }]
|
|
418
|
+
expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 2, to: 1 })).toEqual({
|
|
419
|
+
v: 2,
|
|
420
|
+
})
|
|
421
|
+
expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 1, to: 1 })).toEqual({
|
|
422
|
+
v: 2,
|
|
423
|
+
})
|
|
424
|
+
expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 1, to: 2 })).toBeUndefined()
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
it("reverse=true with custom from/to and key as string", () => {
|
|
428
|
+
const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
|
|
429
|
+
expect(findTruthy(arr, { key: "x", reverse: true, from: 1, to: 1 })).toEqual({ x: 2 })
|
|
430
|
+
expect(findTruthy(arr, { key: "x", reverse: true, from: 1, to: 2 })).toBeUndefined()
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
it("reverse=true with custom from/to and key as number", () => {
|
|
434
|
+
const arr = [[0], [2], [0]]
|
|
435
|
+
expect(findTruthy(arr, { key: 0, reverse: true, from: 1, to: 1 })).toEqual([2])
|
|
436
|
+
expect(findTruthy(arr, { key: 0, reverse: true, from: 1, to: 2 })).toBeUndefined()
|
|
437
|
+
})
|
|
326
438
|
})
|