Home > Software design >  Combine arrays inside map according to label and sum data
Combine arrays inside map according to label and sum data

Time:08-22

I have an array with some streaming channel data, according to the shift (Morning and Afternoon).

I spent the night trying some functions like reduce, but I couldn't understand how it works and stagnated.

var array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}]

I expect to have this output:

The sum total of all streaming channels, divided by the amount of objects value per shift (morning and afternoon)

[{"label":"manha","data":[{"Amazon Prime":"16.66"},{"AppleTV":"0.00"},{"HBO Max":"16.66"},{"Nenhuma":"16.66"},{"Netflix":"43.33"},{"Outro":"6.66"}]},{"label":"tarde","data":[{"Amazon Prime":"5.00"},{"AppleTV":"5.50"},{"HBO Max":"2.50"},{"Nenhuma":"36.00"},{"Netflix":"14.50"},{"Outro":"35.00"}]}]

I would be very grateful if you could help me, and if possible, explain.

CodePudding user response:

This is probably a bit longer then what you have hoped for but it should work.

let newAr = []
for(el of array) {
  const currentLabel = el.label
  let indexOfLabel = -1
  for(let i = 0; i < newAr.length;   i) {
    if(newAr[i].label === currentLabel) indexOfLabel = i
  }
  if(indexOfLabel >= 0) {
    for(let i = 0; i < el.data.length;   i) {
      const key = Object.keys(el.data[i])
      newAr[indexOfLabel].data[i][key] = parseInt(newAr[indexOfLabel].data[i][key])
      newAr[indexOfLabel].data[i][key]  = parseInt(el.data[i][key])
    }
  } else {
    newAr.push(el)
  }
}

const occurrences = array.reduce(function (acc, curr) {
  return acc[curr.label] ?   acc[curr.label] : acc[curr.label] = 1, acc
}, {});

for(el of newAr) {
  for(data of el.data) {
    data[Object.keys(data)] = (data[Object.keys(data)] / occurrences[el.label]).toFixed(2)
  }
}

CodePudding user response:

Let's solve this problem in steps. The first attempt is using reduce to iterate through the result and build something. For simplicity let's get it to build an object where the keys represents the labels. The reason for this is we can use this key to merge similar keys together. On the TODO we observe that:

  • The numerical values are strings not number and do not lend itself for arithmetic operations
  • The subarray is difficult to merge and could do with a conversion to object as well
array.reduce( function (p, c, i, a) {
   let label = c.label;
   if (!(label in p)) {
       p[label] = c.data;
   }
   return p;
}, { } );

// Output:

{
  "manha": [ { "Amazon Prime": "0.00" },
             { "AppleTV": "0.00" },
             { "HBO Max": "25.00" },
             { "Nenhuma": "0.00" },
             { "Netflix": "55.00" },
             { "Outro": "20.00" }
           ],
  "tarde": [ { "Amazon Prime": "10.00" },
             { "AppleTV": "11.00" },
             { "HBO Max": "0.00" },
             { "Nenhuma": "50.00" },
             { "Netflix": "9.00" },
             { "Outro": "20.00" }
           ]
}

For the second attempt, we will:

  • convert more arrays to objects
    • as an object we can make use of object methods such as in to determine whether a key exists or not
  • we can use parseFloat to convert strings to numbers
  • we can start collating the information together This produces a nice set of raw data.
array.reduce( function (p, c, i, a) {
   let label = c.label;
   if (!(label in p)) {
       p[label] = { };
   }
   for (let i = 0; i < c.data.length; i  ) {
       let e = Object.entries(c.data[i]);
       let k = e[0][0];
       let v = parseFloat(e[0][1]);
       if (!(k in p[label])) {
           p[label][k] = [ ];
       }
       p[label][k].push(v);
   }
   return p;
}, { } );

// Output:

{
  "manha": {
    "Amazon Prime": [ 0, 50, 0 ],
    "AppleTV":      [ 0, 0, 0 ],
    "HBO Max":      [ 25, 25, 0 ],
    "Nenhuma":      [ 0, 0, 50 ],
    "Netflix":      [ 55, 25, 50 ],
    "Outro":        [ 20, 0, 0 ]
  },
  "tarde": {
    "Amazon Prime": [ 10, 0 ],
    "AppleTV": [ 11, 0 ],
    "HBO Max": [ 0, 5 ],
    "Nenhuma": [ 50, 25 ],
    "Netflix": [ 9, 20 ],
    "Outro": [ 20, 50 ]
  }
}

For the final step, we just average out the remaining array and convert the numerical result back to a string.

let array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}];

let tmp = array.reduce( function (p, c, i, a) {
   let label = c.label;
   if (!(label in p)) {
       p[label] = { };
   }
   for (let i = 0; i < c.data.length; i  ) {
       let e = Object.entries(c.data[i]);
       let k = e[0][0];
       let v = parseFloat(e[0][1]);
       if (!(k in p[label])) {
           p[label][k] = [ ];
       }
       p[label][k].push(v);
   }
   return p;
}, { } );

let result = Object.entries(tmp).map( ( [label, _data] ) => (
  { label : label,
    data: Object.entries(_data).map( function ( [k, v] ) {
       let obj = { };
       obj[k] = ( v.reduce( (p,c) => p   c ) / v.length ).toFixed(2);
       return obj;
    } )
  }
) );

console.log(JSON.stringify(result, undefined, 2));

  • Related