ES6生成器笛卡尔积

3

我有一个计算笛卡尔积组合的函数:

function cartes1(a, b, c) {
    let arr = []
    for (let i1 of a) {
        for (let i2 of b) {
            for (let i3 of c) {
                arr.push([i1, i2, i3])
            }
        }
    }
    return arr;
}

我想将它转换为生成器以便在需要时停止,因此进行了以下操作:
function* cartes(a, b, c) {
    for (let i1 of a) {
        for (let i2 of b) {
            for (let i3 of c) {
                yield [i1, i2, i3]
            }
        }
    }
}

代码基本相同,但第二个返回错误的结果。
cartes1([1,2,3],[1,2,3],[1,2,3]) // correct
cartes([1,2,3],[1,2,3],[1,2,3])

生成器返回以下内容:
[[ 1, 1, 1 ]
[ 1, 1, 2 ]
[ 1, 1, 3 ]]

生成器函数被调用时,使用yield语句生成值。
cartes(range(1)(3)(1), range(1)(3)(1), range(1)(3)(1))
const range = from => to => function*(step=1) {
    for(let i=from;i<=to;i+=step) {
        yield i
    }
}

我有什么遗漏吗?

谢谢

1个回答

2
你所做的是使用了三个生成器,但如果它们完成了,就无法倒回它们。
为了防止这种情况,你可以返回闭包覆盖的收集值,并在 for 循环中第一次调用生成器。 Generator#next 如果生成器已经到达最终的 return,要么是直接使用该语句,要么是在函数末尾,那么它将返回 donefunction* 说明:
next()方法返回一个对象,其中包含一个value属性,该属性包含生成的值,以及一个done属性,该属性指示生成器是否已将其最后一个值作为布尔值生成。调用带有参数的next()方法将恢复生成器函数的执行,将暂停执行的yield表达式替换为next()中的参数。
在生成器中执行return语句将使生成器完成(即由它返回的对象的done属性将设置为true)。如果返回一个值,则该值将被设置为生成器返回的对象的value属性。
与return语句类似,生成器内部抛出的错误将使生成器完成--除非在生成器的主体内捕获。
当生成器完成时,随后的next调用将不执行该生成器的任何代码,它们只会返回这种形式的对象:{value: undefined, done: true}。

function* cartes(a, b, c) {
    for (let i1 of a()) {
        for (let i2 of b()) {
            for (let i3 of c()) {
                yield [i1, i2, i3];
            }
        }
    }
}

const range = from => to => (step = 1) => function* () {
    for (let i = from; i <= to; i += step) {
        yield i;
    }
};

for (let v of cartes(range(1)(3)(1), range(1)(3)(1), range(1)(3)(1))) {
    console.log(v);
}


这将它们转换为数组。我不想要那个。我想要生成器。我已经在使用for of,但为什么它在第一个数组的第一次迭代后停止了呢? - user2693928
谢谢,但为什么生成器已经完成了。对于(让if1 of a),为什么只返回第一个组合,遍历第一个元素的所有元素不是有意义的吗? - user2693928
i1 还没有完成,但是最后一个 i3 已经完成了。这会阻止获取 i2 的值,因为通过运行最内部的 for 循环,您将不再获得任何值。生成器存储它们的位置,如果完成了...它就停止了。 - Nina Scholz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接