我创建了一个Range
类,它创建了一个生成器函数,用于迭代一系列整数。我的下一步是创建一个生成器函数,该函数迭代每个属性的所有可能的值排列。以下是硬编码示例的简化代码:
// Create the parameter definitions (works perfectly).
const paramDef = {
propA: new Range(1, 2, 3), // [1,2,3] as iterator
propB: new Range(2, 4, 6) // [2,4,6] as iterator
};
// Hardcoded implementation (the goal is to make this generic/re-usable)
function* getUnits(def){
// Foreach value of propA...
for(let valPropA of def.propA.getValues()){
// and foreach value of propB...
for(let valPropB of def.propB.getValues()){
// Yield an instance with the current values...
yield {
propA: valPropA,
propB: valPropB
};
}
}
}
// Iterate one-by-one, creating a permutation of object properties.
for(let unit of getUnits(paramDef)){
console.log(unit);
}
// Outputs:
// {"propA":1,"propB":2}
// {"propA":1,"propB":4}
// {"propA":1,"propB":6}
// {"propA":2,"propB":2}
// {"propA":2,"propB":4}
// {"propA":2,"propB":6}
// {"propA":3,"propB":2}
// {"propA":3,"propB":4}
// {"propA":3,"propB":6}
我已经尝试了很多东西,但我得到的最远的是让第一次迭代正确返回,但没有别的。你如何推广getUnits()
函数以及我应该注意哪些陷阱?
答案 0 :(得分:1)
您可以在属性名称列表中使用递归:
function getObjectsOf(def) {
var keys = Object.keys(def),
o = {};
return rec(keys.length);
function* rec(i) {
if (i <= 0) {
let clone = {}; // I assume you want to yield different objects
for (let k of keys) // or: k in o
clone[k] = o[k];
yield clone;
} else {
let key = keys[i];
for (let value of def[key]) {
o[key] = value;
yield* rec(i-1);
}
}
}
}
如果您正在寻找更高效的解决方案,您可以动态生成&#34;硬编码&#34;版本并使用Function
进行编译 - 请参阅this answer以获取示例。
答案 1 :(得分:0)
如何实施Range
课程?我尝试过这项工作:
class Range{
constructor(){
var args = Array.prototype.slice.call(arguments);
this.getValues = function*(){
for(const num of args){
yield num;
}
};
}
}
使用数组也有效:
'use strict';
const paramDef = {
propA: [1, 2, 3], // [1,2,3] as iterator
propB: [2, 4, 6] // [2,4,6] as iterator
};
// Hardcoded implementation (the goal is to make this generic/re-usable)
function* getUnits(def){
// Foreach value of propA...
for(let valPropA of def.propA){
// and foreach value of propB...
for(let valPropB of def.propB){
// Yield an instance with the current values...
yield {
propA: valPropA,
propB: valPropB
};
}
}
}
// Iterate one-by-one, creating a permutation of object properties.
for(let unit of getUnits(paramDef)){
console.log(unit);
}
所以,我认为问题是你的Range
类实现。
答案 2 :(得分:0)
这是主要功能(下面的完整代码):
// Generic implementation
function* getUnits(def, props, obj){
props = props || [];
// If there are no remaining properties...
if(props.length === 0){
// Then we might be starting out...
if(typeof obj === 'undefined'){
// Grab the property names from the definition.
props = Object.keys(def);
// And create an empty object
obj = {};
} else {
yield obj;
return;
}
}
// Grab the first prop and a copy of the remaining props.
let currentProp = props[0];
let remainingProps = props.slice(1);
// Foreach value of the currentProp...
for(let val of def[currentProp].getValues()){
// Assign the value to a new instance
let currentObj = Object.assign({}, obj, {
[currentProp]: val
});
// Pass the definition, remainingProps, and the new instance to the next level down (smaller subset of properties)
yield* getUnits(def, remainingProps, currentObj);
}
}
我找到的最佳资源是MDN's Example with yield*
演示。如果你想更好地理解ES6发生器,那么绝对值得阅读整篇文章。
@Bergi指示yield
'ed对象实例在所有情况下都相同,理想情况下应该在每个分支处克隆(因此它们是不同的实例)。
整个示例包含在此代码段中(运行它以查看结果)。
// Helper class, provides an iterator from a set of args.
class Range {
constructor() {
this.values = Array.prototype.slice.call(arguments);
}
* getValues() {
for (let i = 0; i < this.values.length; i++) {
yield this.values[i];
}
}
}
// Create the parameter definitions (works perfectly).
const paramDef = {
a: new Range(1, 2, 3),
b: new Range(0, 1),
c: new Range(1, 1, 2, 3, 5)
};
// Generic implementation
function* getUnits(def, props, obj){
props = props || [];
// If there are no remaining properties...
if(props.length === 0){
// Then we might be starting out...
if(typeof obj === 'undefined'){
// Grab the property names from the definition.
props = Object.keys(def);
// And create an empty object
obj = {};
} else {
yield obj;
return;
}
}
// Grab the first prop and a copy of the remaining props.
let currentProp = props[0];
let remainingProps = props.slice(1);
// Foreach value of the currentProp...
for(let val of def[currentProp].getValues()){
// Assign the value to a new instance
let currentObj = Object.assign({}, obj, {
[currentProp]: val
});
// Pass the definition, remainingProps, and the new instance to the next level down (smaller subset of properties)
yield* getUnits(def, remainingProps, currentObj);
}
}
let outputStr = '';
// Iterate one-by-one, creating a permutation of object properties.
for (let unit of getUnits(paramDef)) {
outputStr += JSON.stringify(unit) + '\n';
}
alert(outputStr);
// Outputs:
// See console for the result...