Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions collections/distinct_by.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@
*/
export function distinctBy<T, D>(
array: Iterable<T>,
discriminator: (el: T) => D,
discriminator: (el: T, index: number) => D,
): T[] {
const keys = new Set<D>();
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);
Expand Down
13 changes: 12 additions & 1 deletion collections/distinct_by_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { distinctBy } from "./distinct_by.ts";

function distinctByTest<I>(
array: Array<I>,
selector: (element: I) => unknown,
selector: (element: I, index: number) => unknown,
expected: Array<I>,
message?: string,
) {
Expand Down Expand Up @@ -117,3 +117,14 @@ Deno.test({
);
},
});

Deno.test({
name: "distinctBy() passes index to discriminator",
fn() {
distinctByTest(
[25, "asdf", true],
(_, index) => index > 1,
[25, true],
);
},
});
4 changes: 2 additions & 2 deletions collections/drop_last_while.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
*/
export function dropLastWhile<T>(
iterable: Iterable<T>,
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);
Expand Down
8 changes: 8 additions & 0 deletions collections/drop_last_while_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
});
7 changes: 4 additions & 3 deletions collections/drop_while.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,20 @@
*/
export function dropWhile<T>(
iterable: Iterable<T>,
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);
}
Expand Down
8 changes: 8 additions & 0 deletions collections/drop_while_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
});
5 changes: 3 additions & 2 deletions collections/find_single.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@
*/
export function findSingle<T>(
array: Iterable<T>,
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;
Expand Down
12 changes: 11 additions & 1 deletion collections/find_single_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert";
import { findSingle } from "./find_single.ts";

function findSingleTest<I>(
input: [Array<I>, (element: I) => boolean],
input: [Array<I>, (element: I, index: number) => boolean],
expected: I | undefined,
message?: string,
) {
Expand Down Expand Up @@ -103,3 +103,13 @@ Deno.test({
);
},
});

Deno.test({
name: "findSingle() passes index to predicate",
fn() {
findSingleTest(
[[9, 12, 13], (_, index) => index === 1],
12,
);
},
});
5 changes: 3 additions & 2 deletions collections/first_not_nullish_of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
*/
export function firstNotNullishOf<T, O>(
array: Iterable<T>,
selector: (item: T) => O | undefined | null,
selector: (item: T, index: number) => O | undefined | null,
): NonNullable<O> | 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<O>;
Expand Down
12 changes: 11 additions & 1 deletion collections/first_not_nullish_of_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert";
import { firstNotNullishOf } from "./first_not_nullish_of.ts";

function firstNotNullishOfTest<T, O>(
input: [Array<T>, (el: T) => O | undefined | null],
input: [Array<T>, (el: T, index: number) => O | undefined | null],
expected: NonNullable<O> | undefined,
message?: string,
) {
Expand Down Expand Up @@ -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,
);
},
});
4 changes: 2 additions & 2 deletions collections/join_to_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export type JoinToStringOptions = {
*/
export function joinToString<T>(
array: Iterable<T>,
selector: (el: T) => string,
selector: (el: T, index: number) => string,
options: Readonly<JoinToStringOptions> = {},
): string {
const {
Expand All @@ -101,7 +101,7 @@ export function joinToString<T>(
break;
}

result += selector(el);
result += selector(el, index);
index++;
}

Expand Down
11 changes: 11 additions & 0 deletions collections/join_to_string_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
},
});
5 changes: 3 additions & 2 deletions collections/map_not_nullish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
*/
export function mapNotNullish<T, O>(
array: Iterable<T>,
transformer: (el: T) => O,
transformer: (el: T, index: number) => O,
): NonNullable<O>[] {
const result: NonNullable<O>[] = [];
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<O>);
Expand Down
15 changes: 14 additions & 1 deletion collections/map_not_nullish_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { assertEquals } from "@std/assert";
import { mapNotNullish } from "./map_not_nullish.ts";

function mapNotNullishTest<T, O>(
input: [Array<T>, (el: T) => O | undefined | null],
input: [Array<T>, (el: T, index: number) => O | undefined | null],
expected: Array<O>,
message?: string,
) {
Expand Down Expand Up @@ -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],
);
},
});
19 changes: 10 additions & 9 deletions collections/max_by.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*/
export function maxBy<T>(
array: Iterable<T>,
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
Expand Down Expand Up @@ -63,7 +63,7 @@ export function maxBy<T>(
*/
export function maxBy<T>(
array: Iterable<T>,
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
Expand Down Expand Up @@ -95,7 +95,7 @@ export function maxBy<T>(
*/
export function maxBy<T>(
array: Iterable<T>,
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
Expand Down Expand Up @@ -127,21 +127,22 @@ export function maxBy<T>(
*/
export function maxBy<T>(
array: Iterable<T>,
selector: (el: T) => Date,
selector: (el: T, index: number) => Date,
): T | undefined;
export function maxBy<T>(
array: Iterable<T>,
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 {
let max: T | undefined;
let maxValue: ReturnType<typeof selector> | undefined;
let index = 0;

for (const current of array) {
const currentValue = selector(current);
const currentValue = selector(current, index++);

if (maxValue === undefined || currentValue > maxValue) {
max = current;
Expand Down
11 changes: 11 additions & 0 deletions collections/max_by_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,14 @@ Deno.test({
assertEquals(maxBy(input, (it) => new Date(it)), "February 1, 2022");
},
});

Deno.test({
name: "maxBy() passes index to selector",
fn() {
const input = [4, 3, 2, 1];

const max = maxBy(input, (_, index) => index);

assertEquals(max, 1);
},
});
14 changes: 10 additions & 4 deletions collections/max_of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
*/
export function maxOf<T>(
array: Iterable<T>,
selector: (el: T) => number,
selector: (el: T, index: number) => number,
): number | undefined;
/**
* Applies the given selector to all elements of the provided collection and
Expand Down Expand Up @@ -65,16 +65,22 @@ export function maxOf<T>(
*/
export function maxOf<T>(
array: Iterable<T>,
selector: (el: T) => bigint,
selector: (el: T, index: number) => bigint,
): bigint | undefined;
export function maxOf<T, S extends ((el: T) => number) | ((el: T) => bigint)>(
export function maxOf<
T,
S extends
| ((el: T, index: number) => number)
| ((el: T, index: number) => bigint),
>(
array: Iterable<T>,
selector: S,
): ReturnType<S> | undefined {
let maximumValue: ReturnType<S> | undefined;
let index = 0;

for (const element of array) {
const currentValue = selector(element) as ReturnType<S>;
const currentValue = selector(element, index++) as ReturnType<S>;

if (maximumValue === undefined || currentValue > maximumValue) {
maximumValue = currentValue;
Expand Down
11 changes: 11 additions & 0 deletions collections/max_of_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,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);
},
});
Loading
Loading