如何从JavaScript生成器函数的输出结果中去除重复值
生成器去重解决方案
我有三个生成器函数,第三个是委托生成器:
function* genNumbers() { yield* [1, 2, 2, 2, 3, 4, 5]; } function* genLetters() { yield* ["A", "B", "B", "B", "C", "D"]; } function* genAll() { yield* genNumbers(); yield* genLetters(); } let generator = genAll();
希望调用generator.next()输出所有值时自动去除重复值,预期输出如下:
console.log(generator.next()); // {value: 1, done: false} console.log(generator.next()); // {value: 2, done: false} console.log(generator.next()); // {value: 3, done: false} console.log(generator.next()); // {value: 4, done: false} console.log(generator.next()); // {value: 5, done: false} console.log(generator.next()); // {value: "A", done: false} console.log(generator.next()); // {value: "B", done: false} console.log(generator.next()); // {value: "C", done: false} console.log(generator.next()); // {value: "D", done: false}
方案一:修改委托生成器实现去重
直接在genAll内部维护一个集合记录已输出的值,过滤重复项后再yield:
function* genNumbers() { yield* [1, 2, 2, 2, 3, 4, 5]; } function* genLetters() { yield* ["A", "B", "B", "B", "C", "D"]; } function* genAll() { const seen = new Set(); // 遍历数字生成器,去重后输出 for (const num of genNumbers()) { if (!seen.has(num)) { seen.add(num); yield num; } } // 遍历字母生成器,去重后输出 for (const letter of genLetters()) { if (!seen.has(letter)) { seen.add(letter); yield letter; } } } let generator = genAll(); // 测试输出 console.log(generator.next()); // {value: 1, done: false} console.log(generator.next()); // {value: 2, done: false} console.log(generator.next()); // {value: 3, done: false} console.log(generator.next()); // {value: 4, done: false} console.log(generator.next()); // {value: 5, done: false} console.log(generator.next()); // {value: "A", done: false} console.log(generator.next()); // {value: "B", done: false} console.log(generator.next()); // {value: "C", done: false} console.log(generator.next()); // {value: "D", done: false} console.log(generator.next()); // {value: undefined, done: true}
方案二:通用去重包装生成器
如果不想修改原有生成器,可以写一个通用的去重包装函数,适配任何生成器:
// 通用去重包装生成器 function* dedupeGenerator(generator) { const seen = new Set(); for (const value of generator) { if (!seen.has(value)) { seen.add(value); yield value; } } } function* genNumbers() { yield* [1, 2, 2, 2, 3, 4, 5]; } function* genLetters() { yield* ["A", "B", "B", "B", "C", "D"]; } function* genAll() { yield* genNumbers(); yield* genLetters(); } // 用包装器处理原生成器 let generator = dedupeGenerator(genAll()); // 测试输出 console.log(generator.next()); // {value: 1, done: false} console.log(generator.next()); // {value: 2, done: false} console.log(generator.next()); // {value: 3, done: false} console.log(generator.next()); // {value: 4, done: false} console.log(generator.next()); // {value: 5, done: false} console.log(generator.next()); // {value: "A", done: false} console.log(generator.next()); // {value: "B", done: false} console.log(generator.next()); // {value: "C", done: false} console.log(generator.next()); // {value: "D", done: false} console.log(generator.next()); // {value: undefined, done: true}
思路说明
利用Set数据结构记录已经输出过的值,它的has方法查询效率高(O(1))。遍历生成器的每一个值,仅当值未在Set中时,才将其yield出去并加入Set,确保每次调用next()返回的都是不重复的新值。
内容的提问来源于stack exchange,提问作者Ayman Mirghani
相关产品推荐
相关产品推荐

