2014-11-02 221 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