「ゼッタイにこういうライブラリあるだろ」と思って探したんですが、なかったのでここに書いておきます。ライブラリ化はするまでもないですが、たびたび使うので…
// 自然数列. [0, 1, 2, 3, 4, ...]. 数列の最初の数を引数として受け取ります. const naturalNumbers = function*(n = 0) { while (true) yield n++; }; // フィボナッチ数列. [0, 1, 1, 2, 3, 5, ...]. はじめの2項を受け取ることもできます const fibonacciNumbers = function*(n = 0, m = 1) { while (true) { yield n; [n, m] = [m, n + m]; } }; // 素数列. [2, 3, 5, 7, 11, ...]. キャッシュ機構がついているので高速に回るはずです. const primeNumbers = (() => { const _primeNumbers = ((cache = [2,3,5,7,11,13,17,19,23,29]) => function*() { yield* cache; for (let i = cache[cache.length - 1] + 2; ; i += 2) { let isPrime = true; for (const j of cache) { if (j * j > i) break; if (i % j == 0) { isPrime = false; break; } } if (isPrime) cache.push(yield i); } }); return _primeNumbers(); })(); // 乱数列. [29, 74, 51, 62, ...] のように、引数として受け取った数の範囲の乱数を生成します.デフォルトは0〜99. const randomNumbers = function*(n = 100) { while (true) yield 0 | Math.random() * n; }; // 降下列. [10, 9, 8, 7, ...] のように、引数として受け取った値から1つずつ下がっていきます. const downFrom = function*(n) { while (n >= 0) yield n--; }; // リピート. [0, 0, 0, 0, ...] のように、受け取った値を繰り返し続けます const repeat = function*(n) { while (true) yield n; };
使用例
このように使います
// 自然数を順番に取り出したい for (const n of naturalNumbers()) { console.log(n); }
ついでにいくつか補助関数をつくりました。組み合わせると便利なはずです。
const pair = function*(arr1, arr2) { const item2 = () => arr2.next().value; for (const item of arr1) yield [item, item2()]; }; const map = function*(arr, f) { for (const item of arr) yield f(item); }; const take = (gen, n) => { const res = []; for (const item of gen) { if (n-- <= 0) break; res.push(item); } return res; };
補助関数の使用例:
for (const [index, prime] of pair(naturalNumbers(1), primeNumbers())) { console.log(`${index}番目の素数は${prime}`); } // 小さいほうから素数を10個取り出す console.log(take(primeNumbers(), 10));