LatentDenis
LatentDenis

Reputation: 2991

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?

Upvotes: 0

Views: 17242

Answers (3)

Andriy
Andriy

Reputation: 15442

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

Upvotes: 2

Geeky
Geeky

Reputation: 7498

I think you can do it in pure javascript

check this following snippet

  var obj = [{
            "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 newObj = [];

        MergeObjectProperties(obj);

        function MergeObjectProperties(obj) {
            Object.keys(obj).forEach(function (key) {
                var name = obj[key].name;
                var exists = checkProperty(name, newObj)
                if (newObj.length == 0 || !exists)
                    newObj.push(obj[key]);
                else {
                    newObj[exists]["total"] = obj[key].total + newObj[exists]["total"];
                    newObj[exists]["applicable"] = obj[key].applicable + newObj[exists]["applicable"];
                }
            });
         console.log(newObj);
        }

        function checkProperty(prop, newObj) {
            var result;
            Object.keys(newObj).forEach(function (key) {
                if (newObj[key]["name"] === prop) {
                    result = key
                }
            });
            return result;
        }

Hope this helps

Upvotes: 1

Sushant
Sushant

Reputation: 3669

What I do to simply such things is I use angular forEach and in your case, I'd make three different arrays and fill them up with this information. Then I'd use indexof on them and push them to myNewArray. Its easier to work on simple arrays than array objects.

For example on forEach Angular forEach.

Upvotes: 1

Related Questions