2013-09-23 28 views
6

Potrzebuję wygenerować kompletny zestaw wariantów na podstawie listy N atrybutów, zachowując nazwę atrybutu nienaruszoną.Kartezjański produkt obiektów w javascript

var input = [ 
    { 'colour' : ['red', 'green'] }, 
    { 'material' : ['cotton', 'wool', 'silk'] }, 
    { 'shape' : ['round', 'square', 'rectangle'] } 
]; 

var expected = [ 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'cotton', 'shape': 'rectangle' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'wool', 'shape': 'rectangle' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'round' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'square' }, 
    { 'colour': 'red', 'material': 'silk', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'cotton', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'wool', 'shape': 'rectangle' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'round' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'square' }, 
    { 'colour': 'green', 'material': 'silk', 'shape': 'rectangle' } 
]; 

Istnieje wiele algorytmów wokół produktów kartezjańskich dla tablic, ale nie wydaje się znaleźć jeden dla obiektów, które zachowuje klucze.

Wydajność nie stanowi dużego problemu, ponieważ dla każdego atrybutu nigdy nie będzie więcej niż kilkanaście wartości. Zamówienie nie musi dokładnie odpowiadać expected.

Zrobiłem wstępną próbę opartą na standardowych algorytmów list, ale jestem walczą:

function cartesianProduct(input, current) { 
    if (!input || input.length < 1) { 
     return []; 
    } 

    var head = input[0]; 
    var tail = input.slice(1); 
    var output = []; 

    for (var key in head) { 
     for (var i = 0; i < head[key].length; i++) { 
      if (typeof current == 'undefined') { 
       var current = {}; 
      } 

      current[key] = head[key][i]; 
      var productOfTail = cartesianProduct(tail, current); 
      output.push(current); 
      console.log(current); 
     } 
    } 

    return output; 
} 

console.log(cartesianProduct(input)); 
+0

[A podobne pytanie zostało zadane tutaj] (http://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in -javascript) – Keithamus

+0

jest duży problem w twoim kodzie: nie deklarujesz ja jako var, więc jest uważany za globalny var, a więc zmienić d w funkcji wewnętrznej wywołuje ... – GameAlchemist

Odpowiedz

4

Po pozbyć się „«I»jest globalnym problemem var”, ty można dostać się do wyniku z tym kodem na przykład:

var input = [ 
    { 'colour' : ['red', 'green'] }, 
    { 'material' : ['cotton', 'wool', 'silk'] }, 
    { 'shape' : ['round', 'square', 'rectangle'] } 
]; 

function cartesianProduct(input, current) { 
    if (!input || !input.length) { return []; } 

    var head = input[0]; 
    var tail = input.slice(1); 
    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 (tail.length) { 
       var productOfTail = 
         cartesianProduct(tail, newCurrent); 
       output = output.concat(productOfTail); 
      } else output.push(newCurrent); 
     } 
    }  
    return output; 
} 

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


console.log(cartesianProduct(input)); 
+0

Wiwaty za to, wiedziałem, że był problem z wypychaniem prądu do tablicy wyjściowej, ale nie mogłem zrozumieć dlaczego. –

+0

Nie ma za co. Jak już zrozumiałeś, bez kopiowania, ciągle zmieniasz pojedynczy obiekt w każdym wywołaniu rekursywnym, a więc produkt nie działa. – GameAlchemist