2014-11-02 12 views
5

tôi có một đối tượng có dạng sau (giản thể trường hợp thử nghiệm dưới đây)sản phẩm Descartes javascript thuộc tính đối tượng

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

Tôi muốn tạo ra một sản phẩm Descartes của các thuộc tính sao cho đầu ra là một mảng trong những cách sau form:

// 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 ] 

Làm cách nào để đạt được điều này? Tôi đã làm việc lên các mã sau (dựa trên một sửa đổi mã cho sản phẩm Descartes của mảng từ một bài SO) nhưng tôi dường như được buộc mình trong knots cố gắng để có được điều này để làm việc.

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)); 

Cảm ơn bạn đã giúp bạn với điều này!

+0

Xem http://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in-javascript – Paul

+0

@Paul, trường hợp này khác. Tôi đã thấy các bài viết khác về điều này (và tạo ra mã dựa trên một sửa đổi), nhưng có một sự khác biệt trong trường hợp này, chúng ta có các thuộc tính lồng nhau như trái ngược với mảng mảng. – Jarnal

+0

Vâng, tôi nghĩ có lẽ bạn có thể kết hợp Object.keys() trên các đối tượng con với chức năng cho các sản phẩm của mảng trong câu hỏi khác, và sau đó cấu trúc lại đầu ra từ một mảng các mảng thành một mảng các đối tượng, với, nói 'map' – Paul

Trả lời

6

Ok, chúng ta hãy bắt đầu với một chức năng mà tạo ra một sản phẩm của mảng đã cho:

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; 
} 

Người tiếp theo sử dụng product để chuyển đổi một cái gì đó giống như {a:[1,2], b:[3,4]} vào [{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; 
    }); 
} 

Đối với dữ liệu thử nghiệm của bạn , bạn phải áp dụng nó hai lần:

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

result = objectProduct(result); 

Điều này cung cấp cho bạn đầu ra bạn muốn.

+0

cảm ơn bạn, cảm ơn bạn, cảm ơn bạn! – Jarnal

Các vấn đề liên quan