2014-11-02 14 views
5

ho uno scopo della seguente forma (caso prova semplificata sotto)prodotto cartesiano di javascript proprietà dell'oggetto

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

voglio generare un prodotto cartesiano delle proprietà in modo che l'uscita è un array dei seguenti modulo:

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

Come posso ottenere questo risultato? Ho elaborato il seguente codice (basato su una modifica del codice per il prodotto cartesiano di array da un altro post SO) ma mi sembra che mi leghi in nodi cercando di farlo funzionare.

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

Grazie in anticipo per il vostro aiuto con questo!

+0

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

+0

@Paul, questo caso è diverso. Ho visto gli altri post su questo (e ho creato il codice basato su una modifica), ma c'è una differenza in questo in questo caso, abbiamo nidificato le proprietà degli oggetti anziché l'array degli array. – Jarnal

+0

Sì, stavo pensando che forse potresti combinare Object.keys() sugli oggetti secondari con la funzione per il prodotto cartesiano di array nell'altra domanda e quindi ristrutturare l'output da una matrice di matrici a una matrice di oggetti, con, dite 'map' – Paul

risposta

6

Ok, cominciamo con una funzione che genera un prodotto di determinati array:

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

Il prossimo si usa product convertire qualcosa come {a:[1,2], b:[3,4]} in [{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; 
    }); 
} 

per i dati di test , devi applicarlo due volte:

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

result = objectProduct(result); 

Questo ti dà l'output che volevi.

+0

grazie, grazie, grazie! – Jarnal

Problemi correlati