somebodytolove
somebodytolove

Reputation: 181

JavaScript foreach objects

I'm struggling with some algorithm with javascript. I'm using Vue as framework and state managament. I have an object that needs to be 'calculated' as variants.

For example, I have 3 objects and in those objects some values as array, like so:

"attributes":[
   {
      "title":{
         "text":"Size",
         "value":"1"
      },
      "values":[
         "M",
         "L",
         "X"
      ]
   },
   {
      "title":{
         "text":"Color",
         "value":"2"
      },
      "values":[
         "Red",
         "Green",
         "Black"
      ]
   },
   {
      "title":{
         "text":"Material"
      },
      "values":[
         "Cotton",
      ]
   }
]

So my state for this is obviously attributes. So what I really need to do is to foreach attribute values and create variant for every possible combination, and console.log them. Like so:

M/Red/Cotton, L/Red/Cotton, X/Red/Cotton, M/Green/Cotton, L/Green/Cotton, X/Green/Cotton, M/Black/Cotton, L/Black/Cotton, X/Black/Cotton

So I started function that will only foreach attributes, so I need to foreach values and make that codes (up) for them, but no idea how to proceed. So it looks like:

addVariant: function (text) {
          this.attributes.forEach(element => console.log(element));
        },

Upvotes: 0

Views: 369

Answers (3)

Akash Sarode
Akash Sarode

Reputation: 447

So basically you want to make combinations of attribute.values right? Here's an answer I found for making combinations with arrays of javascripts. https://stackoverflow.com/a/47701395/13095249 I'm not sure how that works I just copied the code.

Coming back to your problem, I would make an array for all attribute.values like

parts = attributes.map(attribute => attribute.values)

and run the code in above answer should give you the desired output

parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));

your addVariant function could look like:

addVariant: function (text) {
  const parts = this.attributes.map(attribute => attribute.values);
  const combinations = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
  console.log(combinations)
},

Upvotes: 2

Shadab
Shadab

Reputation: 1347

Sounds like you want the cartesian product

For your specific case, this is probably what you're looking for,

addVariant: function (text) {
    let cartesian = (...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())), []);
    
    let values = this.attributes.map(attr => attr.values);
    let combinations = cartesian(...values).map(v => v.join('/'));
    console.log(combinations);
},

Upvotes: 4

Hassan Imam
Hassan Imam

Reputation: 22574

You can use array#reduce with array#map and array#flatMap to generate cartesian product of values.

const attributes = [ { "title":{ "text":"Size", "value":"1" }, "values":[ "M", "L", "X" ] }, { "title":{ "text":"Color", "value":"2" }, "values":[ "Red", "Green", "Black" ] }, { "title":{ "text":"Material" }, "values":[ "Cotton", ] } ],
    result = attributes.reduce((r, o, i) => {
      const array = o.values.map(v => v);
      return i ? array.flatMap(v => r.map(w => (w + '\\' + v))): array;
    },[]);
console.log(result.join());
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Related Questions