我最近在计算机爱好者上观看了这个有趣的视频,并决定使用 JavaScript 生成器来实现筛选算法。总的来说,我对 JavaScript 非常有信心,但之前从未直接使用过生成器。
这是我到目前为止所拥有的:
function* nextNaturalNumber(n) {
yield n;
yield* nextNaturalNumber(n + 1);
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
const possiblePrime = g.next().value;
yield possiblePrime;
// here's where I'm stuck:
// how can I filter the values from the nextNaturalNumber-generator stream that are not divisible by 2?
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
正如代码注释中提到的,我一直困惑于如何过滤生成器流中不能被 2 整除的值,从而执行“筛分”操作。有没有一种简单的方法可以在 JavaScript 中执行此操作(如在 Python 中使用
yield from sieve(i for i in s if i%n !=0)
)?
不幸的是,Javascript 没有那么多好的迭代器操作。但是,您可以只创建一个过滤器函数,循环遍历迭代器并产生匹配的值:
function* nextNaturalNumber(n) {
// switch to iterative to avoid stack overflows
while(true) {
yield n;
n ++;
}
}
function* filterIter(iter, pred) {
for (const item of iter) {
if (pred(item)) {
yield item;
}
}
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
const possiblePrime = g.next().value;
yield possiblePrime;
g = filterIter(g, v => v % possiblePrime != 0);
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
通过以下内容,您只能从流中获得奇数值:
do {
val = g.next().value;
} while (!(val%2));
您可以在代码中测试它:
function* nextNaturalNumber(n) {
yield n;
yield* nextNaturalNumber(n + 1);
}
function* sieve(n) {
let count = 0;
let g = nextNaturalNumber(2);
while (count++ < n) {
let val;
do {
val = g.next().value;
} while (!(val%2));
const possiblePrime=val;
yield possiblePrime;
}
}
// print the first 10 primes
for (const prime of sieve(10)) {
console.log(prime);
}
我担心,也许你正在尝试变得比 JS 编码真正理想的 Pythonic 风格。 JS 鼓励明确您正在使用的变量(而不是像 Python 那样将它们隐藏在调用和过滤堆栈中)。 这个怎么样?
//
// You want to look through all the natural numbers...
//
function* nextNaturalNumber(n) {
while(true) {
yield n;
n++;
}
}
function* sieve() {
//
// Keep track of the primes you've seen previously
//
let previousPrimes = [];
for (const possiblePrime of nextNaturalNumber(2)) {
//
// And for each number, check whether it's divisible by any of those primes
//
if (!previousPrimes.find((test) => (possiblePrime % test === 0))) {
//
// If it's not, return it as a prime and add it to the
// primes you've (now) already seen
//
yield possiblePrime;
previousPrimes.push(possiblePrime);
}
}
}
let generator = sieve();
for(let i = 0; i < 10; i++) {
console.log(generator.next().value);
}
从 ECMAScript 2025 开始,我们有了迭代器辅助方法,例如
filter
和 take
,我们可以这样做:
function* sequence(start) { // Don't use recursion
while (true) yield start++;
}
function* sieve() { // Leave out the parameter
let g = sequence(2);
while (true) {
let prime = g.next().value;
yield prime;
g = g.filter(v => v % prime); // an iterator helper method
}
}
// print the first 10 primes
console.log(...sieve().take(10)); // an iterator helper method