Skip to content

Commit 9b2ea23

Browse files
committed
Add unary end signature to integerRange function with implied start=0
1 parent da04151 commit 9b2ea23

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

math/integer_range.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,45 @@ export type IntegerRangeOptions = {
4646
* assertEquals([...integerRange(5, 1, { step: -1 })], [5, 4, 3, 2]);
4747
* ```
4848
*/
49-
export function* integerRange(
49+
export function integerRange(
5050
start: number,
5151
end: number,
5252
options?: IntegerRangeOptions,
53+
): Generator<number, undefined, undefined>;
54+
55+
/**
56+
* Creates a generator that yields integers in a range from 0 to `end`.
57+
*
58+
* Using the default options, yielded numbers are in the interval `[0, end)` with step size `1`.
59+
*
60+
* @param end The end of the range (exclusive by default)
61+
* @param options Options for the range
62+
* @returns A generator yielding integers in the specified range
63+
*
64+
* @example Usage
65+
* ```ts
66+
* import { integerRange } from "@std/math/integer-range";
67+
* import { assertEquals } from "@std/assert";
68+
* assertEquals([...integerRange(5)], [0, 1, 2, 3, 4]);
69+
* ```
70+
*/
71+
export function integerRange(
72+
end: number,
73+
options?: IntegerRangeOptions,
74+
): Generator<number, undefined, undefined>;
75+
// deno-lint-ignore deno-style-guide/exported-function-args-maximum
76+
export function* integerRange(
77+
startOrEnd: number,
78+
endOrOptions?: number | IntegerRangeOptions,
79+
maybeOptions?: IntegerRangeOptions,
5380
): Generator<number, undefined, undefined> {
81+
const hasStart = typeof endOrOptions === "number";
82+
const [start, end, options] = [
83+
hasStart ? startOrEnd : 0,
84+
hasStart ? endOrOptions : startOrEnd,
85+
hasStart ? maybeOptions : endOrOptions,
86+
];
87+
5488
const { step = 1, includeStart = true, includeEnd = false } = options ?? {};
5589
if (step === 0) throw new RangeError("`step` must not be zero");
5690
for (const [k, v] of Object.entries({ start, end, step })) {
@@ -59,12 +93,18 @@ export function* integerRange(
5993
}
6094
}
6195

96+
if (start === end && !(includeStart && includeEnd)) return;
97+
6298
const limitsSign = Math.sign(end - start);
6399
const stepSign = Math.sign(step);
64100
if (limitsSign !== 0 && limitsSign !== stepSign) return;
65101

66102
if (includeStart) yield start;
67-
if (start > end) { for (let i = start + step; i > end; i += step) yield i; }
68-
else for (let i = start + step; i < end; i += step) yield i;
69-
if (includeEnd && (start !== end || !includeStart)) yield end;
103+
104+
let i = 0;
105+
const delta = Math.abs(step);
106+
const maxDelta = Math.abs(end - start);
107+
for (i += delta; i < maxDelta; i += delta) yield start + (i * stepSign);
108+
109+
if (includeEnd && (i * stepSign) + start === end) yield end;
70110
}

math/integer_range_test.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Deno.test("integerRange()", async (t) => {
1010
assertEquals([...range], []);
1111
});
1212

13+
await t.step("only include end (start defaulting to `0`)", () => {
14+
const range = integerRange(5);
15+
assertEquals([...range], [0, 1, 2, 3, 4]);
16+
});
17+
1318
await t.step("`step`", () => {
1419
assertEquals([...integerRange(1, 5, { step: 2 })], [1, 3]);
1520
});
@@ -34,13 +39,9 @@ Deno.test("integerRange()", async (t) => {
3439
});
3540

3641
await t.step("`start` == `end`", () => {
37-
assertEquals([...integerRange(0, 0)], [0]);
38-
assertEquals([
39-
...integerRange(0, 0, { includeStart: true, includeEnd: true }),
40-
], [0]);
41-
assertEquals([
42-
...integerRange(0, 0, { includeStart: false, includeEnd: true }),
43-
], [0]);
42+
assertEquals([...integerRange(0, 0)], []);
43+
assertEquals([...integerRange(0, 0, { includeEnd: true })], [0]);
44+
assertEquals([...integerRange(0, 0, { includeStart: false })], []);
4445

4546
// if _both_ are false, nothing is yielded
4647
assertEquals([
@@ -70,4 +71,17 @@ Deno.test("integerRange()", async (t) => {
7071
"`step` must not be zero",
7172
);
7273
});
74+
75+
await t.step("`includeEnd` with `step`", () => {
76+
assertEquals([...integerRange(0, 2, { step: 2 })], [0]);
77+
assertEquals([...integerRange(0, 2, { step: 2, includeEnd: true })], [
78+
0,
79+
2,
80+
]);
81+
assertEquals([...integerRange(0, 3, { step: 2 })], [0, 2]);
82+
assertEquals([...integerRange(0, 3, { step: 2, includeEnd: true })], [
83+
0,
84+
2,
85+
]);
86+
});
7387
});

0 commit comments

Comments
 (0)