如何创建计数生成器/迭代器级联?

问题描述 投票:0回答:3

较新版本的 JavaScript 允许将 生成器/迭代器

yield
关键字结合使用。


我的问题背景

考虑以下生成器,它“生成”从 0 到 9 的数字(数字):

// generator (produces numbers from 0 to 9, then stops)
function *zcounter() {
  var i = 0;
  while (i<=9) {
    yield i;
    i++;
  }
}

现在我想用它来替换以下函数,该函数使用3个嵌套的

for
循环:

// e.g.: var iArray=[0,0,0];
function IterateCascade1(iArray) {
    var iterations=0;
    for (var x=0; x<=9; x++) {
        iArray[0]=x;
        for (var y=0; y<=9; y++) {
            iArray[1]=y;
            for (var z=0; z<=9; z++) {
                iArray[2]=z;
                logArray(iArray);
                iterations++;
            }
        }
    }
    return iterations;
}

问题

如果您像这样调用上面的函数

console.log("Iterations: "+IterateCascade1([0,0,0]));

然后它会从000到999数1000次,这正是我想要的。

缺点是只能使用3个元素的数组,不能传递更多元素的数组。


为了使用生成器

zcounter()
解决这个问题,我尝试了以下方法:

// e.g.: var iArray=[0,0,0];
function IterateCascade2(iArray) {
    var iterations=0;
    // generate 3 iterators
    var gArray = [];
    for(var i=0; i<iArray.length; i++) {    
        var g=zcounter();
        gArray[i]=g;
    }
    // loop through
    for(var a in gArray) {
        //console.log("a:"+a);
        var g=gArray[a];
        var gnext=g.next();
        while (!gnext.done)
        {
            iArray[a]=gnext.value;
            logArray(iArray);
            gnext=g.next();
            iterations++;
        }
    }
    return iterations;
}

如果您像这样调用上面的函数

console.log("Iterations: "+IterateCascade2([0,0,0]));

那么它只会数 30 次,并且不会像

IterateCascade1
那样遍历所有 1000 个数字。

此外,如果您传递更大的数组,例如

console.log("Iterations: "+IterateCascade2([0,0,0,0]));

然后它会“计算”从 0 到 9 的每个数字,但不会遍历所有 10000 个组合。


问题

我知道不知何故缺少递归。

  • 如何修改
    IterateCascade2
    以便它做正确的事情(循环所有组合并且可以传递任何大小的整数数组)?

注:

为了显示组合,我使用了

function logArray(x) {
    var result="";
    for(var i=0; i<x.length; i++) { result += x[i].toString(); }
    console.log(result);
}

在上面的例子中。您可以使用 3 个浏览器中任意一个的开发者工具或 JSShell 来运行代码。

javascript arrays iterator generator yield
3个回答
2
投票

以下是如何使用给定的生成器(此处称为

digits()
)来通过新的递归生成器(称为
multiDigits()
)获得组合结果:

// generator (produces natural numbers)
function* naturals() {
  for (let i = 0; true; i++) yield i;
}
// Neat way to limit an iterator; here to digits 0..9
const digits = () => naturals().take(10);

function* multiDigits(numDigits) {
    if (--numDigits < 0) return yield [];
    for (const digit of digits()) {
        for (const rest of multiDigits(numDigits)) {
            yield [digit, ...rest];
        }
    }
}

// Get arrays with 2 digits:
for (const result of multiDigits(2)) console.log(...result);

(请注意,代码片段的控制台面板会截断输出 - 检查您实际浏览器的控制台)


2
投票

这是一个递归的解决方案

function iterareIndex(index, array, iterator) {
    var previousValue = array[index];
    for (var i = 0; i < 10; ++i) {
        array[index] = i;
        if (index == array.length - 1) {
            iterator(array);
        } else {
            iterareIndex(index + 1, array, iterator);
        }
    }
    array[index] = previousValue;
}

function IterateCascade2(array){
    iterareIndex(0, array, logArray);
}

顺便说一下,这会给你相同的输出,而且可能更短:

var size = 3;
var prefix = '';
for(var i = 0; i < size; ++i) {
    prefix += '0';
}
for(var i = 0, l = Math.pow(10, 3); i < l; ++i){
    var printableValue = (prefix+i).slice(-size);
    console.log(printableValue);
}

0
投票

更简单的生成器函数有什么缺点吗?这将采用任何数字数组,然后将它们连接成一个数字,每个数字都是占位符。如果它们全为零,则将在数字的开头添加 1。

[5, 6, 9]    // 0 - 568
[0, 0, 13]   // 0 - 12
[0, 0, 0, 0] // 0 - 9999

这是 0 - 999 与 0 - 9999 与 0 - 99999 与 0 - 999999 的基准

将下面的示例复制/粘贴到浏览器控制台中。

// Paste this to the console first and hit Enter function *placeHolders(array) { if (array.every(n => n === 0)) array.unshift(1); let total = Number(array.join("")); for (let i = 0; i < total; i++) yield i; } // Next, paste this to the console and hit Enter [...placeHolders([0, 0, 0, 0, 0, 0])]
p { font: 700 4ch/1.2 "Segoe UI"; color: red; }
<p>Use the browser console. Read the comments in the JavaScript.</p>

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.