2013-09-23 54 views
6

我需要根据N个属性列表生成一组完整的变体,同时保持属性名称不变。javascript中对象的笛卡尔乘积

var input = [ 
    { 'colour' : ['red', 'green'] }, 
    { 'material' : ['cotton', 'wool', 'silk'] }, 
    { 'shape' : ['round', 'square', 'rectangle'] } 
]; 

var expected = [ 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'rectangle' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'rectangle' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'rectangle' } 
]; 

有很多算法周围阵列笛卡尔的产品,但我似乎无法找到一个用于保存密钥对象。

性能不是一个大问题,因为每个属性永远不会超过十几个值。订单不必完全匹配expected

我做了基于对列表的标准算法的初步尝试,但我挣扎:

function cartesianProduct(input, current) { 
    if (!input || input.length < 1) { 
     return []; 
    } 

    var head = input[0]; 
    var tail = input.slice(1); 
    var output = []; 

    for (var key in head) { 
     for (var i = 0; i < head[key].length; i++) { 
      if (typeof current == 'undefined') { 
       var current = {}; 
      } 

      current[key] = head[key][i]; 
      var productOfTail = cartesianProduct(tail, current); 
      output.push(current); 
      console.log(current); 
     } 
    } 

    return output; 
} 

console.log(cartesianProduct(input)); 
+0

[A类似的问题已经被问这里(http://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in -javascript) – Keithamus

+0

你的代码中存在一个大问题:你不会将我声明为var,所以它被认为是一个全局变量,因此改变d在内部函数调用... – GameAlchemist

回答

4

一旦你摆脱了“我'是一个全局变量的问题”,你可以得到的结果与此代码,例如:

var input = [ 
    { 'colour' : ['red', 'green'] }, 
    { 'material' : ['cotton', 'wool', 'silk'] }, 
    { 'shape' : ['round', 'square', 'rectangle'] } 
]; 

function cartesianProduct(input, current) { 
    if (!input || !input.length) { return []; } 

    var head = input[0]; 
    var tail = input.slice(1); 
    var output = []; 

    for (var key in head) { 
     for (var i = 0; i < head[key].length; i++) { 
      var newCurrent = copy(current);   
      newCurrent[key] = head[key][i]; 
      if (tail.length) { 
       var productOfTail = 
         cartesianProduct(tail, newCurrent); 
       output = output.concat(productOfTail); 
      } else output.push(newCurrent); 
     } 
    }  
    return output; 
} 

function copy(obj) { 
    var res = {}; 
    for (var p in obj) res[p] = obj[p]; 
    return res; 
} 


console.log(cartesianProduct(input)); 
+0

干杯,我知道有推送电流到输出数组的问题,但无法解决原因。 –

+0

不客气。正如你已经理解的那样,在不复制的情况下,你会在每次递归调用中更改单个对象,因此产品无法工作。 – GameAlchemist