2014-11-02 224 views
5

我有以下形式的对象(下面简化测试用例)javascript对象属性

var test = { 
     shirts: { 
      sizes: ['large', 'medium'] 
      ,colors:['red', 'blue'] 
     } 
     , trousers: { 
      type: ['formal', 'casual'] 
      , pattern: ['plaid', 'stripes'] 
     } 
    }; 

我要生成的属性的笛卡尔积,使得输出是下面的阵列的笛卡尔乘积形式:

// desired output 

[ {shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'plaid'}} 
    ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'stripes'}} 
    ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'plaid'}} 
    , {shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'stripes'}} 
    ,{shirts:{sizes:'large', color:'blue'}, trousers:{type:'formal', pattern:'plaid'}} 
..... and so on ] 

我该如何做到这一点?我研究了下面的代码(基于从另一个SO帖子修改了数组的笛卡尔积的代码),但我似乎在试图让这个工作起来。

function myCartesianProduct(input, current) { 
    if (!input) { return []; } 


    var head = input[Object.keys(input)[0]]; 

    var tail = objSlice(input); 

    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 (Object.keys(tail).length) { //if tail.length 
       var productOfTail = 
         myCartesianProduct(tail, newCurrent); 
       output = output.concat(productOfTail); 

      } else { 
       output.push(newCurrent); 

      } 
     } 
    } 
    return output; 
} 


function objSlice(obj) { 
    var slicedObj = angular.copy(obj); // copy object using angularJs copy method 
    delete slicedObj[Object.keys(slicedObj)[0]]; //delete the first key 
    return slicedObj; 
}; 

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

console.log(myCartesianProduct(test)); 

在此先感谢您的帮助!

+0

查看http://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in-javascript – Paul 2014-11-02 09:19:15

+0

@保罗,这种情况是不同的。我确实看到了其他帖子(并且基于修改创建了代码),但是在这种情况下,我们有嵌套对象属性而不是数组数组。 – Jarnal 2014-11-02 09:24:12

+0

是的,我想也许你可以将子对象上的Object.keys()与另一个问题中数组的笛卡尔乘积的函数结合起来,然后将输出从一个数组重新组合到一个对象数组中,说'map' – Paul 2014-11-02 09:27:39

回答

6

好了,让我们开始产生给定阵列的产品功能:

function product(args) { 
    if(!args.length) 
     return [[]]; 
    var prod = product(args.slice(1)), r = []; 
    args[0].forEach(function(x) { 
     prod.forEach(function(p) { 
      r.push([x].concat(p)); 
     }); 
    }); 
    return r; 
} 

下一个使用product喜欢的东西{a:[1,2], b:[3,4]}转换为[{a:1,b:3},{a:1,b:4},{a:2,b:3},{a:2,b:4}]

function objectProduct(obj) { 
    var keys = Object.keys(obj), 
     values = keys.map(function(x) { return obj[x] }); 

    return product(values).map(function(p) { 
     var e = {}; 
     keys.forEach(function(k, n) { e[k] = p[n] }); 
     return e; 
    }); 
} 

对于您的测试数据,你必须申请两次:

var result = {}; 
Object.keys(test).forEach(function(k) { 
    result[k] = objectProduct(test[k]) 
}); 

result = objectProduct(result); 

这给你你想要的输出。

+0

谢谢,谢谢,谢谢! – Jarnal 2014-11-03 04:31:23