Home > Software design >  Find and map together data in an Array
Find and map together data in an Array

Time:09-16

I need to map and gather the name - sum values from an array, but I don't know what the best solution would be here and I got stuck. The data that I get looks like this:

{
timestamp:"2022-09-15",
management: [
{ id: 1;
  name: Sam;
  sum: 12;
},
{ id: 2;
  name: Sam;
  sum: 20;
},
{ id: 3;
  name: Sam;
  sum: 30;
},
{ id: 4;
  name: Sam;
  sum: null;
},
{ id: 5;
  name: Mae;
  sum: 456;
}]

What I would like to achieve is this output:

this.labels = ["Sam", "Mae"];
this.sums = [ 62, 456];

So I would like to find and add all sum values that Sam has, and all values that Mae has, and gather them in an array. What would be the recommended way to do this? What I have tried:

interface FinancesUI {
  timestamp: string;
  management: ProductUI[];
}

interface ProductUI {
  id: number;
  name: string;
  sum: number;
}

finances: FinancesUI;
labels = string[];
sums = number[];

  ngOnInit() {
    this.financesService.getProducts()
     .subscribe({
      next: (financesUI: FinancesUI) => {
        this.finances = financesUI;
        
        const allNames = this.finances.management.map((data) => data.name);
        const getSum = this.finances.management.map((data) => data.sum);
        this.labels = [...new Set(allNames)];

        this.finances.management.forEach((management, i = 0) => {
            if (management.name === this.labels[i]) {
              this.sums.push(management.sum);
            }
          })
      }, 
      error: (error) => {
        ...
    }
  });
  }


I get an error "Cannot read property 'push' of undefined". Can someone please help me?

CodePudding user response:

You can do this with reduce https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

const {labels, sum} =  YOUR_OBJECT.management.reduce((acc, curr) => { 
const {name, sum} = curr;
const pos = acc.labels.indexOf(name)
if (pos === -1){
  acc.labels.push(name)
  acc.sums.push(sum)
} else {
  acc.sums[pos]  = sum
}

return acc}, {labels: [], sums: []})

Something like this should work !

CodePudding user response:

this.sums?.push(person.sum);

try adding {?} after sums

CodePudding user response:

Generally speaking. groupBy name and then take the sum for each group.

// like groupBy, but a bit more versatile due to the reducer.
function aggregate(list, getKey, reducer) {
  const map = new Map();
  for (const item of list) {
    const key = getKey(item);
    map.set(key, reducer(map.get(key), item));
  }
  return map;
}


const data = [
  { id: 1, name: "Sam", sum: 12 },
  { id: 2, name: "Sam", sum: 20 },
  { id: 3, name: "Sam", sum: 30 },
  { id: 4, name: "Sam", sum: null },
  { id: 5, name: "Mae", sum: 456 }
];

const sumsByName = aggregate(
  data, 
  item => item.name, //group by Name
  (total=0, item) => total   ( item.sum)  // aggregate some value per group
);

console.log("labels", [...sumsByName.keys()]);
console.log("sums", [...sumsByName.values()]);

  • Related