2014-11-02 25 views
5

I ein Objekt der folgenden Form haben (vereinfachte Testfall unten)kartesisches Produkt von JavaScript-Objekteigenschaften

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

I ein kartesisches Produkt der Eigenschaften erzeugt werden soll, so dass der Ausgang ein Array der folgenden ist 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 ] 

Wie kann ich das erreichen? Ich habe den folgenden Code ausgearbeitet (basierend auf einer Modifikation des Codes für das kartesische Produkt des Arrays von einem anderen SO-Post), aber ich scheine mich in Knoten zu verknoten, um das zum Laufen zu bringen.

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

Vielen Dank im Voraus für Ihre Hilfe mit diesem!

+0

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

+0

@Paul, dieser Fall ist anders. Ich habe die anderen Beiträge dazu gesehen (und den Code basierend auf einer Modifikation erstellt), aber es gibt einen Unterschied darin, dass wir in diesem Fall Objekteigenschaften im Gegensatz zu Arrays von Arrays verschachtelt haben. – Jarnal

+0

Ja, ich dachte, Sie könnten vielleicht Object.keys() auf Unterobjekte mit der Funktion für kartesisches Produkt von Arrays in der anderen Frage kombinieren und dann die Ausgabe von einem Array von Arrays zu einem Array von Objekten restrukturieren, mit sag 'map' – Paul

Antwort

6

Ok, lassen Sie sich mit einer Start-Funktion, die ein Produkt von bestimmten Arrays erzeugt:

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

Die nächsten product nutzt so etwas wie {a:[1,2], b:[3,4]} in [{a:1,b:3},{a:1,b:4},{a:2,b:3},{a:2,b:4}] zu konvertieren:

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

Für Ihre Testdaten , müssen Sie es zweimal anwenden:

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

result = objectProduct(result); 

Dies gibt Ihnen die gewünschte Ausgabe.

+0

danke, danke, danke! – Jarnal

Verwandte Themen