notexactly
notexactly

Reputation: 33

Transform data from one shape to another in Javascript

How would I go about transforming this shape of data below using Javascript (es6 is fine).

From:

[
  {
    name: "Color",
    options: [{ value: "Gold" }, { value: "Space grey" }]
  },
  {
   name: "Size",
     options: [{ value: 32 }, { value: 64 }]
  },
  {
    name: "Width",
    options: [{ value: 100 }, { value: 200 }]
  }
]

To:

[
  {
    properties: {
      Color: "Gold",
      Size: 32,
      Width: 100
    }
  },
  {
    properties: {
      Color: "Gold",
      Size: 32,
      Width: 200
    }
  },
  {
    properties: {
      Color: "Gold",
      Size: 64,
      Width: 100
    }
  },
  {
    properties: {
      Color: "Gold",
      Size: 64,
      Width: 200
    }
  },
  {
    properties: {
      Color: "Space grey",
      Size: 32,
      Width: 100
    }
  },
  {
    properties: {
      Color: "Space grey",
      Size: 32,
      Width: 200
    }
  },
  {
    properties: {
      Color: "Space grey",
      Size: 64,
      Width: 100
    }
  },
  {
    properties: {
      Color: "Space grey",
      Size: 64,
      Width: 200
    }
  }
]

The second shape is every possible combination of options of the first shape.

I'm trying to build a product form that can handle products that have variants e.g. Color, Size, Material etc. Each of those variants can have multiple options. e.g. For Color, they could be Red, Blue, Orange etc. To get this to work I think I need to get a list that generates all possible combinations so that I can attach a price to each.

Would appreciate any help as I'm stumped :(

Below is what I tried. But its the wrong shape.

let variants = [{
    name: "Color",
    options: [{
      value: "Gold"
    }, {
      value: "Space grey"
    }]
  },
  {
    name: "Size",
    options: [{
      value: "32"
    }, {
      value: "64"
    }]
  },
  {
    name: "Width",
    options: [{
      value: "100"
    }, {
      value: "200"
    }]
  }
]

const [primaryOption, ...otherOptions] = variants

let options = []
primaryOption.options.map(x => {
  otherOptions.map(y => {
    y.options.map(z => {
      options = [
        ...options,
        {
          properties: {
            [primaryOption.name]: x.value,
            [y.name]: z.value
          }
        }
      ]
    })
  })
})

console.log(options)

Upvotes: 2

Views: 249

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386550

You could take the cartesian product by iterating the outer array and take the inner array for the values to append objects.

function getCartesian(array) {
    return array.reduce((r, { name, options }) => {
        var temp = [];
        r.forEach(({ property }) =>
            options.forEach(({ value }) => temp.push({ property: Object.assign({}, property, { [name]: value }) }))
        );
        return temp;
    }, [{}]);
}

var data = [{ name: "Color", options: [{ value: "Gold" }, { value: "Space grey" }] }, { name: "Size", options: [{ value: 32 }, { value: 64 }] }, { name: "Width", options: [{ value: 100 }, { value: 200 }] }];

console.log(getCartesian(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Karan
Karan

Reputation: 12619

let variants = [{
    name: "Color",
    options: [{
      value: "Gold"
    }, {
      value: "Space grey"
    }]
  },
  {
    name: "Size",
    options: [{
      value: 32
    }, {
      value: 64
    }]
  },
  {
    name: "Width",
    options: [{
      value: 100
    }, {
      value: 200
    }]
  }
];

let endIndex = variants[0].options.length;
let result = [];

for (let i = 0; i < endIndex; i++) {
  variants.forEach(x => {
    result[i] = result[i] || {properties:{}};
    result[i].properties[x.name] = x.options[i].value;
  });
}

console.log(result);

Upvotes: 0

Jonas Wilms
Jonas Wilms

Reputation: 138257

 let result = [{}];

 for(const {name, options} of input) {
   const previous = result;
   result = [];
   for(const {value} of options) {
      for(const prev of previous)
         result.push({ ...prev, [name]: value });
   }
}

Just use a nested loop to go over all values, and build up a new array with them.

Upvotes: 3

Related Questions