From 6323841636e16b2b5bf9c398a2e2aa6a9a70f4c5 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Tue, 4 Feb 2025 19:41:49 -0600 Subject: [PATCH 1/2] docs(collections): add period after sentence --- collections/permutations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collections/permutations.ts b/collections/permutations.ts index cbe34c4fbe0b..79c5e01a2ab1 100644 --- a/collections/permutations.ts +++ b/collections/permutations.ts @@ -2,7 +2,7 @@ // This module is browser compatible. /** - * Builds all possible orders of all elements in the given array + * Builds all possible orders of all elements in the given array. * Ignores equality of elements, meaning this will always return the same * number of permutations for a given length of input. * From b6b83da75747dfc03981c043d42c93259ac6ec94 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Tue, 4 Feb 2025 20:07:28 -0600 Subject: [PATCH 2/2] feat(collections): add index arg to methods Closes #6288 --- collections/distinct_by.ts | 5 +++-- collections/distinct_by_test.ts | 13 +++++++++++- collections/drop_last_while.ts | 4 ++-- collections/drop_last_while_test.ts | 8 ++++++++ collections/drop_while.ts | 7 ++++--- collections/drop_while_test.ts | 8 ++++++++ collections/find_single.ts | 5 +++-- collections/find_single_test.ts | 12 +++++++++++- collections/first_not_nullish_of.ts | 5 +++-- collections/first_not_nullish_of_test.ts | 12 +++++++++++- collections/join_to_string.ts | 4 ++-- collections/join_to_string_test.ts | 11 +++++++++++ collections/map_not_nullish.ts | 5 +++-- collections/map_not_nullish_test.ts | 15 +++++++++++++- collections/max_by.ts | 25 ++++++++++++------------ collections/max_by_test.ts | 11 +++++++++++ collections/max_of.ts | 20 ++++++++++++------- collections/max_of_test.ts | 11 +++++++++++ collections/min_by.ts | 25 ++++++++++++------------ collections/min_by_test.ts | 11 +++++++++++ collections/min_of.ts | 20 ++++++++++++------- collections/min_of_test.ts | 11 +++++++++++ collections/partition.ts | 7 ++++--- collections/partition_test.ts | 12 +++++++++++- collections/sort_by.ts | 10 +++++----- collections/sort_by_test.ts | 7 +++++++ collections/sum_of.ts | 5 +++-- collections/sum_of_test.ts | 8 ++++++++ collections/take_last_while.ts | 7 ++++--- collections/take_last_while_test.ts | 8 ++++++++ collections/take_while.ts | 5 +++-- collections/take_while_test.ts | 8 ++++++++ 32 files changed, 252 insertions(+), 73 deletions(-) diff --git a/collections/distinct_by.ts b/collections/distinct_by.ts index 99dcd46099de..df24476ff847 100644 --- a/collections/distinct_by.ts +++ b/collections/distinct_by.ts @@ -29,12 +29,13 @@ */ export function distinctBy( array: Iterable, - discriminator: (el: T) => D, + discriminator: (el: T, index: number) => D, ): T[] { const keys = new Set(); const result: T[] = []; + let index = 0; for (const element of array) { - const key = discriminator(element); + const key = discriminator(element, index++); if (!keys.has(key)) { keys.add(key); result.push(element); diff --git a/collections/distinct_by_test.ts b/collections/distinct_by_test.ts index 064e6c7c30b5..de90b14a940b 100644 --- a/collections/distinct_by_test.ts +++ b/collections/distinct_by_test.ts @@ -5,7 +5,7 @@ import { distinctBy } from "./distinct_by.ts"; function distinctByTest( array: Array, - selector: (element: I) => unknown, + selector: (element: I, index: number) => unknown, expected: Array, message?: string, ) { @@ -117,3 +117,14 @@ Deno.test({ ); }, }); + +Deno.test({ + name: "distinctBy() passes index to discriminator", + fn() { + distinctByTest( + [25, "asdf", true], + (_, index) => index > 1, + [25, true], + ); + }, +}); diff --git a/collections/drop_last_while.ts b/collections/drop_last_while.ts index 41d2d14cabe3..dd7a4a185b39 100644 --- a/collections/drop_last_while.ts +++ b/collections/drop_last_while.ts @@ -27,11 +27,11 @@ */ export function dropLastWhile( iterable: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): T[] { const array = Array.isArray(iterable) ? iterable : Array.from(iterable); let offset = array.length - 1; - while (offset >= 0 && predicate(array[offset]!)) { + while (offset >= 0 && predicate(array[offset]!, offset)) { offset--; } return array.slice(0, offset + 1); diff --git a/collections/drop_last_while_test.ts b/collections/drop_last_while_test.ts index 21ce4972704a..ce922a4437c0 100644 --- a/collections/drop_last_while_test.ts +++ b/collections/drop_last_while_test.ts @@ -80,3 +80,11 @@ Deno.test("dropLastWhile() handles a generator", () => { const actual = dropLastWhile(gen(), (i) => i > 30); assertEquals(actual, [20]); }); + +Deno.test("dropLastWhile() passes index to predicate", () => { + const array = [20, 30, 20]; + + const actual = dropLastWhile(array, (_, index) => index > 1); + + assertEquals(actual, [20, 30]); +}); diff --git a/collections/drop_while.ts b/collections/drop_while.ts index bf0e3e5a2a1b..0de5b2a74013 100644 --- a/collections/drop_while.ts +++ b/collections/drop_while.ts @@ -26,19 +26,20 @@ */ export function dropWhile( iterable: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): T[] { if (Array.isArray(iterable)) { - const idx = iterable.findIndex((el) => !predicate(el)); + const idx = iterable.findIndex((el, index) => !predicate(el, index)); if (idx === -1) { return []; } return iterable.slice(idx); } const array: T[] = []; + let index = 0; let found = false; for (const item of iterable) { - if (found || !predicate(item)) { + if (found || !predicate(item, index++)) { found = true; array.push(item); } diff --git a/collections/drop_while_test.ts b/collections/drop_while_test.ts index 3bacb6d8056e..aed33a93c269 100644 --- a/collections/drop_while_test.ts +++ b/collections/drop_while_test.ts @@ -107,3 +107,11 @@ Deno.test("dropWhile() handles a Map", () => { ["f", 6], ]); }); + +Deno.test("dropWhile() passes index to predicate", () => { + const array = [20, 30, 20]; + + const actual = dropWhile(array, (_, index) => index < 1); + + assertEquals(actual, [30, 20]); +}); diff --git a/collections/find_single.ts b/collections/find_single.ts index a009d2ff13f6..0e04bfdd627e 100644 --- a/collections/find_single.ts +++ b/collections/find_single.ts @@ -32,12 +32,13 @@ */ export function findSingle( array: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): T | undefined { let match: T | undefined; let found = false; + let index = 0; for (const element of array) { - if (predicate(element)) { + if (predicate(element, index++)) { if (found) return undefined; found = true; match = element; diff --git a/collections/find_single_test.ts b/collections/find_single_test.ts index cffb4f98da28..e166bbf5817e 100644 --- a/collections/find_single_test.ts +++ b/collections/find_single_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert"; import { findSingle } from "./find_single.ts"; function findSingleTest( - input: [Array, (element: I) => boolean], + input: [Array, (element: I, index: number) => boolean], expected: I | undefined, message?: string, ) { @@ -103,3 +103,13 @@ Deno.test({ ); }, }); + +Deno.test({ + name: "findSingle() passes index to predicate", + fn() { + findSingleTest( + [[9, 12, 13], (_, index) => index === 1], + 12, + ); + }, +}); diff --git a/collections/first_not_nullish_of.ts b/collections/first_not_nullish_of.ts index 1859ccc49f89..6823b9211d42 100644 --- a/collections/first_not_nullish_of.ts +++ b/collections/first_not_nullish_of.ts @@ -33,10 +33,11 @@ */ export function firstNotNullishOf( array: Iterable, - selector: (item: T) => O | undefined | null, + selector: (item: T, index: number) => O | undefined | null, ): NonNullable | undefined { + let index = 0; for (const current of array) { - const selected = selector(current); + const selected = selector(current, index++); if (selected !== null && selected !== undefined) { return selected as NonNullable; diff --git a/collections/first_not_nullish_of_test.ts b/collections/first_not_nullish_of_test.ts index 50650fb8a74f..bb5f184f5d5b 100644 --- a/collections/first_not_nullish_of_test.ts +++ b/collections/first_not_nullish_of_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert"; import { firstNotNullishOf } from "./first_not_nullish_of.ts"; function firstNotNullishOfTest( - input: [Array, (el: T) => O | undefined | null], + input: [Array, (el: T, index: number) => O | undefined | null], expected: NonNullable | undefined, message?: string, ) { @@ -85,3 +85,13 @@ Deno.test({ ); }, }); + +Deno.test({ + name: "firstNotNullishOf() passes index to selector", + fn() { + firstNotNullishOfTest( + [[1, 2, 3, 4], (it, index) => index < 1 ? null : it], + 2, + ); + }, +}); diff --git a/collections/join_to_string.ts b/collections/join_to_string.ts index 4bd833190dcf..1e885b44fdd9 100644 --- a/collections/join_to_string.ts +++ b/collections/join_to_string.ts @@ -77,7 +77,7 @@ export type JoinToStringOptions = { */ export function joinToString( array: Iterable, - selector: (el: T) => string, + selector: (el: T, index: number) => string, options: Readonly = {}, ): string { const { @@ -101,7 +101,7 @@ export function joinToString( break; } - result += selector(el); + result += selector(el, index); index++; } diff --git a/collections/join_to_string_test.ts b/collections/join_to_string_test.ts index 00eb82634a99..1e67252f30c9 100644 --- a/collections/join_to_string_test.ts +++ b/collections/join_to_string_test.ts @@ -144,3 +144,14 @@ Deno.test({ assertEquals(out, "result: Kim and others are winners"); }, }); + +Deno.test({ + name: "joinToString() passes index to selector", + fn() { + const arr = ["Kim", "Anna", "Tim"]; + + const out = joinToString(arr, (it, index) => it + index); + + assertEquals(out, "Kim0,Anna1,Tim2"); + }, +}); diff --git a/collections/map_not_nullish.ts b/collections/map_not_nullish.ts index b28ff5ac10f2..783d91d83a2d 100644 --- a/collections/map_not_nullish.ts +++ b/collections/map_not_nullish.ts @@ -33,12 +33,13 @@ */ export function mapNotNullish( array: Iterable, - transformer: (el: T) => O, + transformer: (el: T, index: number) => O, ): NonNullable[] { const result: NonNullable[] = []; + let index = 0; for (const element of array) { - const transformedElement = transformer(element); + const transformedElement = transformer(element, index++); if (transformedElement !== undefined && transformedElement !== null) { result.push(transformedElement as NonNullable); diff --git a/collections/map_not_nullish_test.ts b/collections/map_not_nullish_test.ts index 6c25ec280d3b..3e69100c33c5 100644 --- a/collections/map_not_nullish_test.ts +++ b/collections/map_not_nullish_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert"; import { mapNotNullish } from "./map_not_nullish.ts"; function mapNotNullishTest( - input: [Array, (el: T) => O | undefined | null], + input: [Array, (el: T, index: number) => O | undefined | null], expected: Array, message?: string, ) { @@ -90,3 +90,16 @@ Deno.test({ ); }, }); + +Deno.test({ + name: "mapNotNullish() passes index to transformer", + fn() { + mapNotNullishTest( + [ + [1, 2, 3, 4], + (it, index) => index === 1 ? null : it + index, + ], + [1, 5, 7], + ); + }, +}); diff --git a/collections/max_by.ts b/collections/max_by.ts index 171df9b1eda3..7e3c9e6e9227 100644 --- a/collections/max_by.ts +++ b/collections/max_by.ts @@ -31,7 +31,7 @@ */ export function maxBy( array: Iterable, - selector: (el: T) => number, + selector: (el: T, index: number) => number, ): T | undefined; /** * Returns the first element that is the largest value of the given function or @@ -63,7 +63,7 @@ export function maxBy( */ export function maxBy( array: Iterable, - selector: (el: T) => string, + selector: (el: T, index: number) => string, ): T | undefined; /** * Returns the first element that is the largest value of the given function or @@ -95,7 +95,7 @@ export function maxBy( */ export function maxBy( array: Iterable, - selector: (el: T) => bigint, + selector: (el: T, index: number) => bigint, ): T | undefined; /** * Returns the first element that is the largest value of the given function or @@ -127,26 +127,26 @@ export function maxBy( */ export function maxBy( array: Iterable, - selector: (el: T) => Date, + selector: (el: T, index: number) => Date, ): T | undefined; export function maxBy( array: Iterable, selector: - | ((el: T) => number) - | ((el: T) => string) - | ((el: T) => bigint) - | ((el: T) => Date), + | ((el: T, index: number) => number) + | ((el: T, index: number) => string) + | ((el: T, index: number) => bigint) + | ((el: T, index: number) => Date), ): T | undefined { if (Array.isArray(array)) { const length = array.length; if (length === 0) return undefined; let max: T = array[0]!; - let maxValue = selector(max); + let maxValue = selector(max, 0); for (let i = 1; i < length; i++) { const current = array[i]!; - const currentValue = selector(current); + const currentValue = selector(current, i); if (currentValue > maxValue) { max = current; maxValue = currentValue; @@ -161,12 +161,13 @@ export function maxBy( if (first.done) return undefined; + let index = 0; let max: T = first.value; - let maxValue = selector(max); + let maxValue = selector(max, index++); let next = iter.next(); while (!next.done) { - const currentValue = selector(next.value); + const currentValue = selector(next.value, index++); if (currentValue > maxValue) { max = next.value; maxValue = currentValue; diff --git a/collections/max_by_test.ts b/collections/max_by_test.ts index 73be52745c94..a3f02d2ffcb5 100644 --- a/collections/max_by_test.ts +++ b/collections/max_by_test.ts @@ -191,3 +191,14 @@ Deno.test("maxBy() handles Map values", () => { const max = maxBy(input.values(), (i) => i.age); assertEquals(max, { age: 45 }); }); + +Deno.test({ + name: "maxBy() passes index to selector", + fn() { + const input = [4, 3, 2, 1]; + + const max = maxBy(input, (_, index) => index); + + assertEquals(max, 1); + }, +}); diff --git a/collections/max_of.ts b/collections/max_of.ts index 7f4b7a0d181c..fa30726057a9 100644 --- a/collections/max_of.ts +++ b/collections/max_of.ts @@ -32,7 +32,7 @@ */ export function maxOf( array: Iterable, - selector: (el: T) => number, + selector: (el: T, index: number) => number, ): number | undefined; /** * Applies the given selector to all elements of the provided collection and @@ -65,9 +65,14 @@ export function maxOf( */ export function maxOf( array: Iterable, - selector: (el: T) => bigint, + selector: (el: T, index: number) => bigint, ): bigint | undefined; -export function maxOf number) | ((el: T) => bigint)>( +export function maxOf< + T, + S extends + | ((el: T, index: number) => number) + | ((el: T, index: number) => bigint), +>( array: Iterable, selector: S, ): ReturnType | undefined { @@ -75,11 +80,11 @@ export function maxOf number) | ((el: T) => bigint)>( const length = array.length; if (length === 0) return undefined; - let max = selector(array[0]!) as ReturnType; + let max = selector(array[0]!, 0) as ReturnType; if (Number.isNaN(max)) return max; for (let i = 1; i < length; i++) { - const currentValue = selector(array[i]!) as ReturnType; + const currentValue = selector(array[i]!, i) as ReturnType; if (currentValue > max) { max = currentValue; } else if (Number.isNaN(currentValue)) { @@ -90,17 +95,18 @@ export function maxOf number) | ((el: T) => bigint)>( return max; } + let index = 0; const iter = array[Symbol.iterator](); const first = iter.next(); if (first.done) return undefined; - let max = selector(first.value) as ReturnType; + let max = selector(first.value, index++) as ReturnType; if (Number.isNaN(max)) return max; let next = iter.next(); while (!next.done) { - const currentValue = selector(next.value) as ReturnType; + const currentValue = selector(next.value, index++) as ReturnType; if (currentValue > max) { max = currentValue; } else if (Number.isNaN(currentValue)) { diff --git a/collections/max_of_test.ts b/collections/max_of_test.ts index 78c0956c7b6e..73150883fc83 100644 --- a/collections/max_of_test.ts +++ b/collections/max_of_test.ts @@ -142,3 +142,14 @@ Deno.test("maxOf() handles infinity", () => { assertEquals(actual, Infinity); }); + +Deno.test({ + name: "maxBy() passes index to selector", + fn() { + const input = [4, 3, 2, 1]; + + const max = maxOf(input, (it, index) => it * index); + + assertEquals(max, 4); + }, +}); diff --git a/collections/min_by.ts b/collections/min_by.ts index 9c25371e4b49..1967c1497a1e 100644 --- a/collections/min_by.ts +++ b/collections/min_by.ts @@ -31,7 +31,7 @@ */ export function minBy( array: Iterable, - selector: (el: T) => number, + selector: (el: T, index: number) => number, ): T | undefined; /** * Returns the first element that is the smallest value of the given function or @@ -63,7 +63,7 @@ export function minBy( */ export function minBy( array: Iterable, - selector: (el: T) => string, + selector: (el: T, index: number) => string, ): T | undefined; /** * Returns the first element that is the smallest value of the given function or @@ -95,7 +95,7 @@ export function minBy( */ export function minBy( array: Iterable, - selector: (el: T) => bigint, + selector: (el: T, index: number) => bigint, ): T | undefined; /** * Returns the first element that is the smallest value of the given function or @@ -125,26 +125,26 @@ export function minBy( */ export function minBy( array: Iterable, - selector: (el: T) => Date, + selector: (el: T, index: number) => Date, ): T | undefined; export function minBy( array: Iterable, selector: - | ((el: T) => number) - | ((el: T) => string) - | ((el: T) => bigint) - | ((el: T) => Date), + | ((el: T, index: number) => number) + | ((el: T, index: number) => string) + | ((el: T, index: number) => bigint) + | ((el: T, index: number) => Date), ): T | undefined { if (Array.isArray(array)) { const length = array.length; if (length === 0) return undefined; let min: T = array[0]!; - let minValue = selector(min); + let minValue = selector(min, 0); for (let i = 1; i < length; i++) { const current = array[i]!; - const currentValue = selector(current); + const currentValue = selector(current, i); if (currentValue < minValue) { min = current; minValue = currentValue; @@ -154,17 +154,18 @@ export function minBy( return min; } + let index = 0; const iter = array[Symbol.iterator](); const first = iter.next(); if (first.done) return undefined; let min: T = first.value; - let minValue = selector(min); + let minValue = selector(min, index++); let next = iter.next(); while (!next.done) { - const currentValue = selector(next.value); + const currentValue = selector(next.value, index++); if (currentValue < minValue) { min = next.value; minValue = currentValue; diff --git a/collections/min_by_test.ts b/collections/min_by_test.ts index dd56d2442c69..491a1af96fff 100644 --- a/collections/min_by_test.ts +++ b/collections/min_by_test.ts @@ -192,3 +192,14 @@ Deno.test("minBy() handles Map values", () => { const min = minBy(input.values(), (i) => i.age); assertEquals(min, { age: 23 }); }); + +Deno.test({ + name: "minBy() passes index to selector", + fn() { + const input = [4, 3, 2, 1]; + + const max = minBy(input, (_, index) => index); + + assertEquals(max, 4); + }, +}); diff --git a/collections/min_of.ts b/collections/min_of.ts index e95f9c99e25c..1aa851c1668e 100644 --- a/collections/min_of.ts +++ b/collections/min_of.ts @@ -32,7 +32,7 @@ */ export function minOf( array: Iterable, - selector: (el: T) => number, + selector: (el: T, index: number) => number, ): number | undefined; /** * Applies the given selector to all elements of the given collection and @@ -65,9 +65,14 @@ export function minOf( */ export function minOf( array: Iterable, - selector: (el: T) => bigint, + selector: (el: T, index: number) => bigint, ): bigint | undefined; -export function minOf number) | ((el: T) => bigint)>( +export function minOf< + T, + S extends + | ((el: T, index: number) => number) + | ((el: T, index: number) => bigint), +>( array: Iterable, selector: S, ): ReturnType | undefined { @@ -75,11 +80,11 @@ export function minOf number) | ((el: T) => bigint)>( const length = array.length; if (length === 0) return undefined; - let min = selector(array[0]!) as ReturnType; + let min = selector(array[0]!, 0) as ReturnType; if (Number.isNaN(min)) return min; for (let i = 1; i < length; i++) { - const currentValue = selector(array[i]!) as ReturnType; + const currentValue = selector(array[i]!, i) as ReturnType; if (currentValue < min) { min = currentValue; } else if (Number.isNaN(currentValue)) { @@ -90,17 +95,18 @@ export function minOf number) | ((el: T) => bigint)>( return min; } + let index = 0; const iter = array[Symbol.iterator](); const first = iter.next(); if (first.done) return undefined; - let min = selector(first.value) as ReturnType; + let min = selector(first.value, index++) as ReturnType; if (Number.isNaN(min)) return min; let next = iter.next(); while (!next.done) { - const currentValue = selector(next.value) as ReturnType; + const currentValue = selector(next.value, index++) as ReturnType; if (currentValue < min) { min = currentValue; } else if (Number.isNaN(currentValue)) { diff --git a/collections/min_of_test.ts b/collections/min_of_test.ts index e379b4e65fc1..6fe46d651da8 100644 --- a/collections/min_of_test.ts +++ b/collections/min_of_test.ts @@ -142,3 +142,14 @@ Deno.test("minOf() handles minus infinity", () => { assertEquals(actual, -Infinity); }); + +Deno.test({ + name: "minOf() passes index to selector", + fn() { + const input = [4, 3, 2, 1]; + + const max = minOf(input, (it, index) => it * index); + + assertEquals(max, 0); + }, +}); diff --git a/collections/partition.ts b/collections/partition.ts index 11b6776f901c..47d93ed2c6c4 100644 --- a/collections/partition.ts +++ b/collections/partition.ts @@ -65,17 +65,18 @@ export function partition( */ export function partition( array: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): [T[], T[]]; export function partition( array: Iterable, - predicate: (el: unknown) => boolean, + predicate: (el: unknown, index: number) => boolean, ): [unknown[], unknown[]] { const matches: Array = []; const rest: Array = []; + let index = 0; for (const element of array) { - if (predicate(element)) { + if (predicate(element, index++)) { matches.push(element); } else { rest.push(element); diff --git a/collections/partition_test.ts b/collections/partition_test.ts index 85aec9f9ee3d..08367e94cb2c 100644 --- a/collections/partition_test.ts +++ b/collections/partition_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert"; import { partition } from "./partition.ts"; function partitionTest( - input: [Array, (element: I) => boolean], + input: [Array, (element: I, index: number) => boolean], expected: [Array, Array], message?: string, ) { @@ -112,3 +112,13 @@ Deno.test({ assertEquals(odd, [1, 3, 5]); }, }); + +Deno.test({ + name: "partition() passes index to predicate", + fn() { + partitionTest( + [[2, 4, 6], (_, index) => index % 2 === 0], + [[2, 6], [4]], + ); + }, +}); diff --git a/collections/sort_by.ts b/collections/sort_by.ts index 0dfb024c4298..102d6d335a2b 100644 --- a/collections/sort_by.ts +++ b/collections/sort_by.ts @@ -118,10 +118,10 @@ export type SortByOptions = { export function sortBy( iterator: Iterable, selector: - | ((el: T) => number) - | ((el: T) => string) - | ((el: T) => bigint) - | ((el: T) => Date), + | ((el: T, index: number) => number) + | ((el: T, index: number) => string) + | ((el: T, index: number) => bigint) + | ((el: T, index: number) => Date), options?: SortByOptions, ): T[] { const array = Array.isArray(iterator) ? iterator : Array.from(iterator); @@ -130,7 +130,7 @@ export function sortBy( const indices: number[] = new Array(len); for (let i = 0; i < len; i++) { - selected[i] = selector(array[i]!); + selected[i] = selector(array[i]!, i); indices[i] = i; } diff --git a/collections/sort_by_test.ts b/collections/sort_by_test.ts index 6984e0753b2d..faa301f52cfe 100644 --- a/collections/sort_by_test.ts +++ b/collections/sort_by_test.ts @@ -331,3 +331,10 @@ Deno.test({ assertEquals(sorted.length, 10000); }, }); + +Deno.test({ + name: "sortBy() passes index to selector", + fn() { + assertEquals(sortBy([2, 3, 1], (_, index) => -index), [1, 3, 2]); + }, +}); diff --git a/collections/sum_of.ts b/collections/sum_of.ts index e0237badcf2f..682e21d45f8b 100644 --- a/collections/sum_of.ts +++ b/collections/sum_of.ts @@ -30,12 +30,13 @@ */ export function sumOf( array: Iterable, - selector: (el: T) => number, + selector: (el: T, index: number) => number, ): number { let sum = 0; + let index = 0; for (const i of array) { - sum += selector(i); + sum += selector(i, index++); } return sum; diff --git a/collections/sum_of_test.ts b/collections/sum_of_test.ts index 21876f6c8a5a..59a592855398 100644 --- a/collections/sum_of_test.ts +++ b/collections/sum_of_test.ts @@ -130,3 +130,11 @@ Deno.test("sumOf() handles Infinity", () => { assertEquals(actual, Infinity); }); + +Deno.test("sumOf() passes index to selector", () => { + const array = [1, 2, 3]; + + const actual = sumOf(array, (_, index) => index); + + assertEquals(actual, 3); +}); diff --git a/collections/take_last_while.ts b/collections/take_last_while.ts index d50efdae6d2c..a8f33dbd5c4b 100644 --- a/collections/take_last_while.ts +++ b/collections/take_last_while.ts @@ -26,18 +26,19 @@ */ export function takeLastWhile( iterable: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): T[] { if (Array.isArray(iterable)) { let offset = iterable.length; - while (0 < offset && predicate(iterable[offset - 1] as T)) { + while (0 < offset && predicate(iterable[offset - 1] as T, offset - 1)) { offset--; } return iterable.slice(offset); } + let index = 0; const result: T[] = []; for (const el of iterable) { - if (predicate(el)) { + if (predicate(el, index++)) { result.push(el); } else { result.length = 0; diff --git a/collections/take_last_while_test.ts b/collections/take_last_while_test.ts index 6d032e53c840..3945e05d9f74 100644 --- a/collections/take_last_while_test.ts +++ b/collections/take_last_while_test.ts @@ -116,3 +116,11 @@ Deno.test("takeLastWhile() gets from last matching element from a generator", () const actual = takeLastWhile(gen(), (i) => i !== 2 && i !== 4); assertEquals(actual, [5, 6]); }); + +Deno.test("takeLastWhile() passes the index to the predicate", () => { + const arr = [1, 2, 3, 4]; + + const actual = takeLastWhile(arr, (_, index) => index > 1); + + assertEquals(actual, [3, 4]); +}); diff --git a/collections/take_while.ts b/collections/take_while.ts index b02dcac0ec23..c36f1b9bdf28 100644 --- a/collections/take_while.ts +++ b/collections/take_while.ts @@ -28,11 +28,12 @@ */ export function takeWhile( iterable: Iterable, - predicate: (el: T) => boolean, + predicate: (el: T, index: number) => boolean, ): T[] { + let index = 0; const result: T[] = []; for (const element of iterable) { - if (!predicate(element)) { + if (!predicate(element, index++)) { break; } result.push(element); diff --git a/collections/take_while_test.ts b/collections/take_while_test.ts index 00e9bc32adce..65e42fae3e39 100644 --- a/collections/take_while_test.ts +++ b/collections/take_while_test.ts @@ -90,3 +90,11 @@ Deno.test("takeWhile() handles a Map", () => { ["c", 3], ]); }); + +Deno.test("takeWhile() passes the index to the predicate", () => { + const arr = [1, 2, 3, 4]; + + const actual = takeWhile(arr, (_, index) => index < 1); + + assertEquals(actual, [1]); +});