-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from jsr-core/add-nth
feat(nth): add `nth` operator
- Loading branch information
Showing
14 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* Returns the n-th element of an iterable. If the length of the iterable is less, returns `undefined`. | ||
* | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/async/first/~/first first} to get the first element of an iterable. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/async/last/~/last last} to get the last element of an iterable. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/async/find/~/find find} to get the first element that matches a predicate. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/nth/~/nth nth} to get the n-th element synchronously. | ||
* | ||
* @param iterable The iterable to get the first element from. | ||
* @param index The index of the element to get (0-based). | ||
* @returns The first element of the iterable, or `undefined` if the iterable is empty. | ||
* @throws {RangeError} If `index` is not zero nor a positive safe integer. | ||
* | ||
* @example | ||
* ```ts | ||
* import { nth } from "@core/iterutil/async/nth"; | ||
* | ||
* const value = await nth([1, 2, 3], 1); | ||
* console.log(value); // 2 | ||
* ``` | ||
*/ | ||
export function nth<T>( | ||
iterable: Iterable<T> | AsyncIterable<T>, | ||
index: number, | ||
): Promise<T | undefined> { | ||
if (index < 0 || !Number.isSafeInteger(index)) { | ||
throw new RangeError( | ||
`index must be 0 or positive safe integer, but got ${index}.`, | ||
); | ||
} | ||
return async function () { | ||
let i = 0; | ||
for await (const value of iterable) { | ||
if (index === i++) { | ||
return value; | ||
} | ||
} | ||
return undefined; | ||
}(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { assertEquals, assertThrows } from "@std/assert"; | ||
import { assertType, type IsExact } from "@std/testing/types"; | ||
import { toAsyncIterable } from "./to_async_iterable.ts"; | ||
import { nth } from "./nth.ts"; | ||
|
||
Deno.test("last", async (t) => { | ||
await t.step("with async iterable", async (t) => { | ||
await t.step("with non empty iterable", async () => { | ||
const result = await nth(toAsyncIterable([1, 2, 3, 4, 5]), 2); | ||
const expected = 3; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
|
||
await t.step("with empty iterable", async () => { | ||
const result = await nth(toAsyncIterable([] as number[]), 2); | ||
const expected = undefined; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
}); | ||
|
||
await t.step("with iterable", async (t) => { | ||
await t.step("with non empty iterable", async () => { | ||
const result = await nth([1, 2, 3, 4, 5], 2); | ||
const expected = 3; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
|
||
await t.step("with empty iterable", async () => { | ||
const result = await nth([] as number[], 2); | ||
const expected = undefined; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
}); | ||
|
||
await t.step("throws RangeError", async (t) => { | ||
await t.step("if the index is not 0 nor positive safe integer", () => { | ||
assertThrows(() => nth([], NaN), RangeError); | ||
assertThrows(() => nth([], Infinity), RangeError); | ||
assertThrows(() => nth([], -Infinity), RangeError); | ||
assertThrows(() => nth([], -1), RangeError); | ||
assertThrows(() => nth([], 1.1), RangeError); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* Returns the n-th element of an iterable. If the length of the iterable is less, returns `undefined`. | ||
* | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/first/~/first first} to get the first element of an iterable. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/last/~/last last} to get the last element of an iterable. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/find/~/find find} to get the first element that matches a predicate. | ||
* Use {@linkcode https://jsr.io/@core/iterutil/doc/async/nth/~/nth nth} to get the n-th element asynchronously. | ||
* | ||
* @param iterable The iterable to get the first element from. | ||
* @param index The index of the element to get (0-based). | ||
* @returns The first element of the iterable, or `undefined` if the iterable is empty. | ||
* @throws {RangeError} If `index` is not zero nor a positive safe integer. | ||
* | ||
* @example | ||
* ```ts | ||
* import { nth } from "@core/iterutil/nth"; | ||
* | ||
* const result = nth([1, 2, 3], 1); | ||
* console.log(result); // 2 | ||
* ``` | ||
*/ | ||
export function nth<T>(iterable: Iterable<T>, index: number): T | undefined { | ||
if (index < 0 || !Number.isSafeInteger(index)) { | ||
throw new RangeError( | ||
`index must be 0 or positive safe integer, but got ${index}.`, | ||
); | ||
} | ||
let i = 0; | ||
for (const value of iterable) { | ||
if (index === i++) { | ||
return value; | ||
} | ||
} | ||
return undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { assertEquals, assertThrows } from "@std/assert"; | ||
import { assertType, type IsExact } from "@std/testing/types"; | ||
import { nth } from "./nth.ts"; | ||
|
||
Deno.test("nth", async (t) => { | ||
await t.step("with non empty iterable", () => { | ||
const result = nth([1, 2, 3, 4, 5], 2); | ||
const expected = 3; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
|
||
await t.step("with empty iterable", () => { | ||
const result = nth([] as number[], 2); | ||
const expected = undefined; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
|
||
await t.step("throws RangeError", async (t) => { | ||
await t.step("if the index is not 0 nor positive safe integer", () => { | ||
assertThrows(() => nth([], NaN), RangeError); | ||
assertThrows(() => nth([], Infinity), RangeError); | ||
assertThrows(() => nth([], -Infinity), RangeError); | ||
assertThrows(() => nth([], -1), RangeError); | ||
assertThrows(() => nth([], 1.1), RangeError); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { nth as base } from "@core/iterutil/async/nth"; | ||
|
||
/** | ||
* Returns an operator that returns the n-th element of an iterable. If the length of the iterable is less, returns `undefined`. | ||
* | ||
* See {@linkcode https://jsr.io/@core/iterutil/doc/async/nth/~/nth nth} for native nth. | ||
* | ||
* @example | ||
* ```ts | ||
* import { pipe } from "@core/pipe"; | ||
* import { nth } from "@core/iterutil/pipe/async/nth"; | ||
* | ||
* const value = await pipe( | ||
* [1, 2, 3], | ||
* nth(1), | ||
* ); | ||
* console.log(value); // 2 | ||
* ``` | ||
*/ | ||
export function nth( | ||
index: number, | ||
): <T>(iterable: Iterable<T> | AsyncIterable<T>) => Promise<T | undefined> { | ||
return (iterable) => base(iterable, index); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { assertEquals } from "@std/assert"; | ||
import { assertType, type IsExact } from "@std/testing/types"; | ||
import { pipe } from "@core/pipe"; | ||
import { nth } from "./nth.ts"; | ||
|
||
Deno.test("nth", async (t) => { | ||
await t.step("usage", async () => { | ||
const result = await pipe([1, 2, 3], nth(1)); | ||
const expected = 2; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { nth as base } from "@core/iterutil/nth"; | ||
|
||
/** | ||
* Returns an operator that returns the n-th element of an iterable. If the length of the iterable is less, returns `undefined`. | ||
* | ||
* See {@linkcode https://jsr.io/@core/iterutil/doc/nth/~/nth nth} for native nth. | ||
* | ||
* @example | ||
* ```ts | ||
* import { pipe } from "@core/pipe"; | ||
* import { nth } from "@core/iterutil/pipe/nth"; | ||
* | ||
* const value = pipe( | ||
* [1, 2, 3], | ||
* nth(1), | ||
* ); | ||
* console.log(value); // 2 | ||
* ``` | ||
*/ | ||
export function nth( | ||
index: number, | ||
): <T>(iterable: Iterable<T>) => T | undefined { | ||
return (iterable) => base(iterable, index); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { assertEquals } from "@std/assert"; | ||
import { assertType, type IsExact } from "@std/testing/types"; | ||
import { pipe } from "@core/pipe"; | ||
import { nth } from "./nth.ts"; | ||
|
||
Deno.test("nth", async (t) => { | ||
await t.step("usage", () => { | ||
const result = pipe([1, 2, 3], nth(1)); | ||
const expected = 2; | ||
assertEquals(result, expected); | ||
assertType<IsExact<typeof result, number | undefined>>(true); | ||
}); | ||
}); |