VolcovMeter VolcovMeter - 1 month ago 6
AngularJS Question

AngularJS: How to check if value exists in array of objects?

I'm trying to write a function that iterates through an array of objects, and pushes in new ones (ones that have a unique name), while updating ones that have already been seen.

Say for example, I have this array:

$scope.myArray = [
{ "name": "Apple", "total": 16, "applicable": 21 },
{ "name": "Cherry", "total": 12, "applicable": 27 },
{ "name": "Plum", "total": 14, "applicable": 21 },
{ "name": "Apple", "total": 16, "applicable": 21 },
{ "name": "Cherry", "total": 12, "applicable": 27 },
{ "name": "Plum", "total": 14, "applicable": 21 },
{ "name": "Banana", "total": 14, "applicable": 21 },
];


By the end of the function, the new array should be:

$scope.myNewArray = [
{ "name": "Apple", "total": 32, "applicable": 42},
{ "name": "Cherry", "total": 24, "applicable": 54},
{ "name": "Plum", "total": 28, "applicable": 42},
{ "name": "Banana", "total": 14, "applicable": 21 },
];


Here's what I have so far:

$scope.myArray = [
{ "name": "Apple", "total": 16, "applicable": 21 },
{ "name": "Cherry", "total": 12, "applicable": 27 },
{ "name": "Plum", "total": 14, "applicable": 21 },
{ "name": "Apple", "total": 16, "applicable": 21 },
{ "name": "Cherry", "total": 12, "applicable": 27 },
{ "name": "Plum", "total": 14, "applicable": 21 },
{ "name": "Banana", "total": 14, "applicable": 21 },
];

$scope.myNewArray = [];

$scope.myArray.filter( function () {

var i = $scope.myNewArray.indexOf($scope.myArray.name);

if ($scope.myNewArray.indexOf($scope.myArray.name) < 0)
$scope.myNewArray.push($scope.myArray);

else {
$scope.myNewArray[i].total += $scope.myArray.total;
$scope.myNewArray[i].applicable += $scope.myArray.applicable;
}
});


The problem I'm encountering is everything gets pushed into the new array. That and I believe my else statement where I'm adding the values to the previous record might be wrong.

Also, hard-coding an array for each name doesn't work as this is just a simple example with a small dataset.

Can anyone lend a hand?

Answer

try this approach:

  1. create object where keys are name property and total along with applicable are already calculated (Array.prototype.reduce)
  2. Iterate over keys of previously created object and transform it back to array (Object.keys and Array.prototype.map)

var res = {};
res = Object.keys([
    { "name": "Apple", "total": 16, "applicable": 21 },
    { "name": "Cherry", "total": 12, "applicable": 27 },
    { "name": "Plum", "total": 14, "applicable": 21 },
    { "name": "Apple", "total": 16, "applicable": 21 },
    { "name": "Cherry", "total": 12, "applicable": 27 },
    { "name": "Plum", "total": 14, "applicable": 21 },
    { "name": "Banana", "total": 14, "applicable": 21 },
].reduce(function (res, item) {
  if (res[item.name]) {
    res[item.name].total += item.total;
    res[item.name].applicable += item.applicable;
  }
  else {
    res[item.name] = item;
  }
  return res; 
}, res)).map(function(key) {
  return res[key];
});
console.log(res);

adding less hardcoded solution:

var myArray = [
  { "name": "Apple", "total": 16, "applicable": 21 },
  { "name": "Cherry", "total": 12, "applicable": 27 },
  { "name": "Plum", "total": 14, "applicable": 21 },
  { "name": "Apple", "total": 16, "applicable": 21 },
  { "name": "Cherry", "total": 12, "applicable": 27 },
  { "name": "Plum", "total": 14, "applicable": 21 },
  { "name": "Banana", "total": 14, "applicable": 21 },
];

var res = {};
  
// add keys for loopable integers which will be summed   
var loopables = Object.keys(myArray[0]).filter(function (key) {
  return Number.isInteger(myArray[0][key]);
});

res = Object.keys(myArray.reduce(function (res, item) {
  if (res[item.name]) {
    loopables.forEach(function (loopableKey) {
      res[item.name][loopableKey] += item[loopableKey];
    });
    
  }
  else {
    res[item.name] = item;
  }
  return res; 
}, res)).map(function(key) {
  return res[key];
});
console.log(res);

here I only rely on the main key name, the rest integer properties are automatically summed, by iterating over loopables keys array, calculated at the beginning

plunker with Angular: https://plnkr.co/edit/MRr2QRULG8TYs2CqA1By?p=preview