通过遍历未知数量的数组来创建 JavaScript 个对象的笛卡尔积(幂集?)

Create cartesian product (powerset?) of JavaScript objects by looping through unknown number of arrays

我是初学者,所以如果这是微不足道的,请原谅我的无知。

我有一个 javascript 长度未知的对象,每个 属性 的值都是一个数组(对我来说也是长度未知的)。例如:

var obj = {"varA":[1,2,3],
           "varB":['good','bad'],
           "varC":[0,100],
           "varD":['low','med','high']
          }

我想遍历每个属性并为每个 属性 值的组合创建一个新对象。如果我知道我可以强行使用 for 循环的属性数量,但是有没有一种方法可以在不知道要硬编码多少循环的情况下进行枚举?

我基本上想做这种事情:

var oblist = [];
for (a in varA){
 for (b in varB){
  for (c in varC){
   for (d in varD){
    oblist.push({"varA":varA[a], "varB":varB[b], "varC":varC[c], "varD":varD[d]});
   }
  }
 }
}

因此 oblist 将包含如下对象:

{"varA":1, "varB":"good", "varC":0, "varD":"low"}
{"varA":1, "varB":"good", "varC":0, "varD":"med"}
...
{"varA":3, "varB":"bad", "varC":100, "varD":"high"}

谢谢!

编辑: 看,我不是在寻求 for-loop 或索引语法帮助。我在问如果我不知道对象中属性的数量该怎么办(例如 varA、varB、varC、varD、varE,我知道我可以拥有 varZZ),所以我不能只是努力-代码 4 for 循环。有没有办法使用 obj[Object.keys(obj)[i]].length?

var obj = {"varA":[1,2,3],
           "varB":['good','bad'],
           "varC":[0,100],
           "varD":['low','med','high']
          }
 
// flatten the object into an array so it's easier to work with
var obj2list = function(obj) {
  var list = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      list.push({
        name: key,
        val: obj[key]
      });
    }
  }
  return list;
};
 
// implement your favorite version of clone...this isn't particular fast
var cloneObj = function(obj) {
  return JSON.parse(JSON.stringify(obj));
}
 
var iterateAndPopulateCombo = function(currentObj, listToIterate, result) {
  if (listToIterate.length == 0) {
    result.push(currentObj);
  } else {
    listToIterate[0].val.forEach(function(d) {
      var newObj = cloneObj(currentObj);
      newObj[listToIterate[0].name] = d;
      iterateAndPopulateCombo(newObj, listToIterate.slice(1), result);
    })
  }
}
 
var list = obj2list(obj);
var result = [];
iterateAndPopulateCombo({}, list, result);
console.log(JSON.stringify(result));
document.body.appendChild(document.createTextNode(JSON.stringify(result)));

您需要的组合是对象中所有数组的 cartesian product,这里是 fiddle 显示它的实际效果:

http://jsfiddle.net/sifriday/qmyxhhny/2/

代码...

// I think the combo you're after is known as cartesian product
// Here's a function to do it, from:
// 
// It needs Underscore.js
function cartesianProductOf() {
    return _.reduce(arguments, function(a, b) {
        return _.flatten(_.map(a, function(x) {
            return _.map(b, function(y) {
                return x.concat([y]);
            });
        }), true);
    }, [ [] ]);
};

// Here's your object
var obj = {"varA":[1,2,3],
           "varB":['good','bad'],
           "varC":[0,100],
           "varD":['low','med','high']
          }

// Now I extract the arrays from your object
var idx, jdx, keys = Object.keys(obj), arrays = [], result1 = [], result2 = []
for (idx in keys) {
    var key = keys[idx]
    var arr = obj[key]
    arrays.push(arr)
}

// We can calculate the combos of the obj, but this isn't annotated. 
result1 = cartesianProductOf.apply(null, arrays)

// Now turn these back into annotated objects.
for (idx in result1) {
    var tmp = result1[idx], obj = {}
    for (jdx in tmp) {
       obj[keys[jdx]] = tmp[jdx]
    }
    result2.push(obj)
}

// Done!
console.log(result2)

我认为可以通过一些努力来解决这个问题;您或许可以确保注释发生在笛卡尔积内。