Use statics in Range

This commit is contained in:
Andrew Morris
2023-06-23 10:18:06 +10:00
parent 540b25225a
commit ba1390d653
27 changed files with 134 additions and 139 deletions

View File

@@ -1,64 +1,6 @@
import { primes } from "../projEuler/helpers/primes.ts";
export default function range<T>(iterable: Iterable<T>) {
return new Range(iterable);
}
// TODO: Static methods
export function Range_from<T = never>(
iter?: Iterable<T> | Iterator<T> | (() => Iterable<T>),
) {
if (iter === undefined) {
return range([]);
}
if (typeof iter === "function") {
return range(iter());
}
// TODO: `in` operator
if (hasKey(iter, Symbol.iterator)) {
return range(iter);
}
if (hasKey(iter, "next")) {
return Range_fromIterator(iter);
}
never(iter);
}
export function Range_fromIterable<T = never>(iterable: Iterable<T> = []) {
return new Range<T>(iterable);
}
export function Range_fromIterator<T = never>(iterator: Iterator<T>) {
return new Range<T>({
[Symbol.iterator]: () => iterator,
});
}
export function Range_numbers(start = 0, end?: number) {
if (end === undefined) {
return range((function* () {
for (let i = start;; i++) {
yield i;
}
})());
}
return range((function* () {
for (let i = start; i < end; i++) {
yield i;
}
})());
}
export function Range_primes() {
return new Range(primes());
}
export class Range<T = never> implements Iterable<T> {
export default class Range<T = never> implements Iterable<T> {
iterable: Iterable<T>;
constructor(iterable: Iterable<T>) {
@@ -85,7 +27,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
count() {
@@ -189,7 +131,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
flatMap<MappedT>(fn: (x: T) => Iterable<MappedT>) {
@@ -203,7 +145,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
flatten<U>(this: Range<Iterable<U>>) {
@@ -217,7 +159,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
filter(fn: (x: T) => boolean) {
@@ -231,7 +173,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
// TODO: Negative indexes
@@ -275,7 +217,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
append<U>(newItems: Iterable<U>) {
@@ -286,7 +228,7 @@ export class Range<T = never> implements Iterable<T> {
yield* newItems;
}
return range(res());
return new Range(res());
}
prepend<U>(newItems: Iterable<U>) {
@@ -297,7 +239,7 @@ export class Range<T = never> implements Iterable<T> {
yield* iterable;
}
return range(res());
return new Range(res());
}
zip<U>(other: Iterable<U>) {
@@ -319,7 +261,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
skip(n: number) {
@@ -343,7 +285,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
reduce<S>(state: S, fn: (state: S, x: T) => S) {
@@ -367,7 +309,7 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
window(len: number) {
@@ -387,7 +329,7 @@ export class Range<T = never> implements Iterable<T> {
memory.push(value);
}
yield range(memory);
yield new Range(memory);
let i = 0;
@@ -397,7 +339,7 @@ export class Range<T = never> implements Iterable<T> {
const memoryCopy = memory;
const iCopy = i;
yield range((function* () {
yield new Range((function* () {
for (let j = 1; j <= len; j++) {
yield memoryCopy[(iCopy + j) % len];
}
@@ -408,7 +350,60 @@ export class Range<T = never> implements Iterable<T> {
}
}
return range(res());
return new Range(res());
}
static fromConversion<T = never>(
iter?: Iterable<T> | Iterator<T> | (() => Iterable<T>),
) {
if (iter === undefined) {
return new Range([]);
}
if (typeof iter === "function") {
return new Range(iter());
}
// TODO: `in` operator
if (hasKey(iter, Symbol.iterator)) {
return new Range(iter);
}
if (hasKey(iter, "next")) {
return Range.fromIterator(iter);
}
never(iter);
}
static from<T = never>(iterable: Iterable<T> = []) {
return new Range<T>(iterable);
}
static fromIterator<T = never>(iterator: Iterator<T>) {
return new Range<T>({
[Symbol.iterator]: () => iterator,
});
}
static numbers(start = 0, end?: number) {
if (end === undefined) {
return new Range((function* () {
for (let i = start;; i++) {
yield i;
}
})());
}
return new Range((function* () {
for (let i = start; i < end; i++) {
yield i;
}
})());
}
static primes() {
return new Range(primes());
}
}

View File

@@ -1,14 +1,14 @@
// test_output! [0,2,[2,3,5,7,11],[11,31,41,61,71],547]
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import { primes } from "../projEuler/helpers/primes.ts";
export default function main() {
return [
range([]).count(),
range([1, 2, 3]).limit(2).count(),
[...range(primes()).limit(5)],
[...range(primes()).filter((p) => p % 5 === 1).limit(5)],
range(primes()).at(100),
Range.from([]).count(),
Range.from([1, 2, 3]).limit(2).count(),
[...Range.from(primes()).limit(5)],
[...Range.from(primes()).filter((p) => p % 5 === 1).limit(5)],
Range.from(primes()).at(100),
];
}

View File

@@ -1,7 +1,7 @@
//! bench()
import { Range_primes } from "./helpers/range.ts";
import Range from "./helpers/Range.ts";
export default function main() {
return Range_primes().at(4999);
return Range.primes().at(4999);
}

View File

@@ -1,9 +1,9 @@
//! test_output(233168)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return Range_numbers(0, 1000)
return Range.numbers(0, 1000)
.filter((x) => x % 3 === 0 || x % 5 === 0)
.sum();
}

View File

@@ -1,9 +1,9 @@
//! test_output_slow(142913828922)
import { Range_primes } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return Range_primes()
return Range.primes()
.while((p) => p < 2_000_000)
.sum();
}

View File

@@ -1,16 +1,16 @@
//! test_output_slow(76576500)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import { factorizeAsPowers } from "./helpers/primes.ts";
export default function main() {
return range(triangularNumbers())
return Range.from(triangularNumbers())
.filter((tri) => countFactors(tri) > 500)
.first();
}
function countFactors(n: number): number {
return range(factorizeAsPowers(n))
return Range.from(factorizeAsPowers(n))
.map(([_, power]) => power + 1)
.product();
}

View File

@@ -1,6 +1,6 @@
//! test_output("5537376230")
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
const nums = [
@@ -106,7 +106,7 @@ export default function main() {
53503534226472524250874054075591789781264330331690n,
];
return range(nums)
return Range.from(nums)
.bigSum()
.toString()
.slice(0, 10);

View File

@@ -1,7 +1,7 @@
//! test_output(1366)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return range(`${2n ** 1000n}`).map(Number).sum();
return Range.from(`${2n ** 1000n}`).map(Number).sum();
}

View File

@@ -1,4 +1,4 @@
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import SillyBigInt from "./helpers/SillyBigInt.ts";
export default function main() {
@@ -8,7 +8,7 @@ export default function main() {
sbi.add(sbi);
}
return range(sbi.toString())
return Range.from(sbi.toString())
.map(Number)
.sum();
}

View File

@@ -1,9 +1,9 @@
//! test_output_slow(21124)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return Range_numbers(1, 1001)
return Range.numbers(1, 1001)
.map(toWords)
.map(countEligibleLetters)
.sum();

View File

@@ -1,9 +1,9 @@
//! test_output(4613732)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return range(fibonacci())
return Range.from(fibonacci())
.while((x) => x < 4_000_000)
.filter((x) => x % 2 === 0)
.sum();

View File

@@ -1,9 +1,9 @@
//! test_output(648)
import range, { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
const factorial100 = Range_numbers(2, 101).map(BigInt).bigProduct();
const factorial100 = Range.numbers(2, 101).map(BigInt).bigProduct();
return range(`${factorial100}`).map(Number).sum();
return Range.from(`${factorial100}`).map(Number).sum();
}

View File

@@ -1,10 +1,10 @@
//! test_output_slow(31626)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import { properFactorSum } from "./helpers/properFactorSum.ts";
export default function main() {
return Range_numbers(2, 10_000)
return Range.numbers(2, 10_000)
.filter(isAmicable)
.sum();
}

View File

@@ -1,6 +1,6 @@
//! test_output(2970)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return nameListScore([
@@ -20,14 +20,14 @@ export default function main() {
function nameListScore(names: string[]) {
names.sort();
return range(names)
return Range.from(names)
.indexed()
.map(([i, name]) => (i + 1) * nameScore(name))
.sum();
}
function nameScore(name: string) {
return range(name)
return Range.from(name)
.map((c) => c.codePointAt(0)! - "A".codePointAt(0)! + 1)
.sum();
}

View File

@@ -1,15 +1,15 @@
//! test_output_slow(4179871)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import { properFactorSum } from "./helpers/properFactorSum.ts";
export default function main() {
const abundantNumbers = [
...Range_numbers(1, 28123)
...Range.numbers(1, 28123)
.filter(isAbundant),
];
return Range_numbers(1, 28123)
return Range.numbers(1, 28123)
.indexed()
.flatMap(function* ([_i, n]) {
// Uncomment to see progress (program takes ~50s with a release build)

View File

@@ -1,11 +1,11 @@
//! test_output_slow([2,7,8,3,9,1,5,4,6,0])
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
// TODO: Faster algorithm (it's not necessary to enumerate the permutations).
export default function main() {
return range(permsOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])).at(999_999);
return Range.from(permsOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])).at(999_999);
}
function* permsOf(nums: number[]) {

View File

@@ -1,14 +1,14 @@
//! test_output(4782)
import assert from "../helpers/assert.ts";
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
// TODO: Remove the temptation pull out this constant (optimization to eval
// known expressions).
const threshold = 10n ** 999n;
const result = range(fibonacci())
const result = Range.from(fibonacci())
.indexed()
.filter(([_, x]) => x > threshold)
.first();

View File

@@ -1,13 +1,13 @@
import assert from "../helpers/assert.ts";
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import SillyBigInt from "./helpers/SillyBigInt.ts";
export default function main() {
const res = range(fibonacci())
const res = Range.from(fibonacci())
.indexed()
.filter(([_, fib]) => fib.toString().length >= 1000)
.first();
assert(res !== undefined);
return res[0];

View File

@@ -1,6 +1,6 @@
//! test_output(669171001)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
// There's an analytic solution for this, but that kinda eliminates the need to
// write code altogether. We're showcasing programming techniques here, not
@@ -14,8 +14,8 @@ export default function () {
[1, 7, 21],
];
let sum = range(rayStarters)
.map(([a, b, c]) => range(ray(a, b, c)).limit(501))
let sum = Range.from(rayStarters)
.map(([a, b, c]) => Range.from(ray(a, b, c)).limit(501))
.flatten()
.sum();

View File

@@ -1,12 +1,12 @@
//! test_output_slow(9183)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
let nums = [];
for (const a of Range_numbers(2, 101)) {
for (const b of Range_numbers(2, 101)) {
for (const a of Range.numbers(2, 101)) {
for (const b of Range.numbers(2, 101)) {
nums.push(BigInt(a) ** BigInt(b));
}
}

View File

@@ -1,11 +1,11 @@
//! test_output_slow(443839)
import range, { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return Range_numbers(10, 1_000_000)
return Range.numbers(10, 1_000_000)
.flatMap(function* (i) {
const digitsPowSum = range(`${i}`)
const digitsPowSum = Range.from(`${i}`)
.map((d) => Number(d) ** 5)
.sum();

View File

@@ -1,14 +1,14 @@
//! test_output(232792560)
import range, { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
import { factorize } from "./helpers/primes.ts";
export default function main() {
const factors = Range_numbers(2, 21)
const factors = Range.numbers(2, 21)
.map(factorize)
.reduce([] as number[], (n, i) => lcm(n, [...i]));
return range(factors).product();
return Range.from(factors).product();
}
function lcm(leftFactors: number[], rightFactors: number[]): number[] {

View File

@@ -1,15 +1,15 @@
//! test_output(25164150)
import { Range_numbers } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return squareOfSum(100) - sumOfSquares(100);
}
function sumOfSquares(n: number) {
return Range_numbers(1, n + 1).map((x) => x ** 2).sum();
return Range.numbers(1, n + 1).map((x) => x ** 2).sum();
}
function squareOfSum(n: number) {
return Range_numbers(1, n + 1).sum() ** 2;
return Range.numbers(1, n + 1).sum() ** 2;
}

View File

@@ -1,7 +1,7 @@
//! test_output_slow(104743)
import { Range_primes } from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
return Range_primes().at(10_000);
return Range.primes().at(10_000);
}

View File

@@ -1,6 +1,6 @@
//! test_output(23514624000)
import range from "../helpers/range.ts";
import Range from "../helpers/Range.ts";
export default function main() {
const digits = [
@@ -26,7 +26,7 @@ export default function main() {
"71636269561882670428252483600823257530420752963450",
];
return range(digits)
return Range.from(digits)
.flatten()
.window(13)
.map((w) => w.map(Number).product())

View File

@@ -2,11 +2,11 @@
import quickSort from "./helpers/quickSort.ts";
import randish from "./helpers/randish.ts";
import { Range_from } from "./helpers/range.ts";
import Range from "./helpers/Range.ts";
export default function main() {
let nums = [
...Range_from(randish())
...Range.from(randish())
.map((x) => Math.floor(8_000 * x))
.limit(10_000),
];

View File

@@ -2,12 +2,12 @@
import BinaryTree from "./helpers/BinaryTree.ts";
import randish from "./helpers/randish.ts";
import range from "./helpers/range.ts";
import Range from "./helpers/Range.ts";
export default function main() {
let tree = new BinaryTree<number>();
for (const rand of range(randish()).limit(5_000)) {
for (const rand of Range.from(randish()).limit(5_000)) {
tree.insert(Math.floor(4_000 * rand));
}