Add up identical keys within an array containing multiple objects

I am working with an array of objects that look like this:

[
    {
        'name': 'P1',
        'value': 150
    },
    {
        'name': 'P1',
        'value': 150
    },
    {
        'name': 'P2',
        'value': 200
    },
    {
        'name': 'P3',
        'value': 450
    }
]

My goal is to sum up the values for objects with the same name (and possibly perform other mathematical operations like calculating averages). For the given example, the desired result would be:

[
    {
        'name': 'P1',
        'value': 300
    },
    {
        'name': 'P2',
        'value': 200
    },
    {
        'name': 'P3',
        'value': 450
    }
]

Answer №1

To begin, loop through the array and store the 'name' in a property of another object. If the property already exists, add the 'value' to its current value; otherwise, initialize the property with the 'value'. After creating this object, iterate through the properties and push them into a new array.

Below is an example of the code:

var obj = [
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P2', 'value': 200 },
    { 'name': 'P3', 'value': 450 }
];

var holder = {};

obj.forEach(function(d) {
  if (holder.hasOwnProperty(d.name)) {
    holder[d.name] = holder[d.name] + d.value;
  } else {
    holder[d.name] = d.value;
  }
});

var obj2 = [];

for (var prop in holder) {
  obj2.push({ name: prop, value: holder[prop] });
}

console.log(obj2);

I trust this explanation clarifies any confusion you may have had.

Answer №2

A cutting-edge ES2024 method for grouping by name

To begin, utilize the Map.groupBy function to group your array based on the name attribute into a Map. Each key in the map corresponds to a distinct name from your objects, while the associated value is an array of objects with that specific name attribute. Subsequently, apply Array.from() on the grouped Map to convert it into an array of objects. For each object in this new array, you can sum up the values with matching name keys using .reduce():

const sumByKey = (arr, key, value) => {
  const grouped = Map.groupBy(arr, o => o[key]);
  return Array.from(
    grouped.values(),
    group => group.reduce((acc, obj) => ({...obj, [value]: (acc[value] ?? 0) + obj[value]}), {})
  );
}

const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];
console.log(sumByKey(arr, 'name', 'value')); // [ { "name": "P1", "value": 300 }, { "name": "P2", "value": 200 }, { "name": "P3", "value": 450 } ]

An innovative ES6 tactic for grouping by name:

You can transform your object array into a Map using .reduce() technique. The resultant Map contains key-value pairs where each key represents the name, and the corresponding value signifies the accumulated sum of values for that particular name key. Thereafter, effortlessly convert the Map back into an array utilizing Array.from(), enabling you to execute a mapping function that will convert the keys/values of the Map into objects:

const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];

const res = Array.from(arr.reduce(
  (m, {name, value}) => m.set(name, (m.get(name) || 0) + value), new Map
), ([name, value]) => ({name, value}));
console.log(res);

The above process may appear concise and slightly complex. To enhance clarity, consider encapsulating it within a function for better understanding. If code readability is a priority, employing for...of can simplify comprehension. The following function also proves beneficial for grouping or summing keys with spaces within them:

const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];

const sumByKey = (arr, key, value) => {
  const map = new Map();
  for(const obj of arr) {
    const currSum = map.get(obj[key]) || 0;
    map.set(obj[key], currSum + obj[value]);
  }
  const res = Array.from(map, ([k, v]) => ({[key]: k, [value]: v}));
  return res;
}

console.log(sumByKey(arr, 'name', 'value')); // 'name' = value to group by, 'value' = value to sum


Enhanced Grouping beyond just name:

Consider this strategy capable of handling other interconnected properties apart from solely name (ensuring identical keys and values in both objects for effective "grouping"). This method involves iterating through the array and reducing it to a Map containing key-value pairs. Each key in the fresh Map represents a string composed of all property values intended for grouping. Therefore, detecting existing object keys indicates duplicates, thereby allowing addition of the current object's value to the stored object. Finally, leverage Array.from() to transition from a Map of key-value pairs to exclusively an array of values:

const arr = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];

const res = Array.from(arr.reduce((acc, {value, ...r}) => {
  const key = JSON.stringify(r);
  const current = acc.get(key) || {...r, value: 0};  
  return acc.set(key, {...current, value: current.value + value});
}, new Map).values());
console.log(res);

Answer №3

You can utilize the Array.reduce() method to aggregate results in each iteration.

var items = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];

var total = items.reduce(function(accumulator, currentValue){
    var existingItem = accumulator.filter(function(obj){
        return obj.name == currentValue.name;
    }).pop() || {name:currentValue.name, value: 0};
    
    existingItem.value += currentValue.value;
    accumulator.push(existingItem);
    return accumulator;
}, []);

console.log(total);

Answer №4

The process of simplifying complex reduce functions with Array, Map, and Set can be achieved in a more straightforward way as shown below:

const summed = arr.reduce((acc, cur, i) => {
  const item = i > 0 && acc.find(({name}) => name === cur.name)
  if (item) item.value += cur.value;
  else acc.push({ name: cur.name, value: cur.value }); // do not include current element here
  return acc;
}, [])
console.log(arr); // input array remains unchanged
console.log(summed);
<script>
  const arr = [{
      'name': 'P1',
      'value': 150
    },
    {
      'name': 'P1',
      'value': 150
    },
    {
      'name': 'P2',
      'value': 200
    },
    {
      'name': 'P3',
      'value': 450
    }
  ]
</script>

Answer №5

After running the code provided by @Vignesh Raja, I noticed that while I did get the "sum" as expected, there were duplicates in the result. To resolve this issue, I had to eliminate the duplicates using the method outlined below.

Here is the original array:

arr=[{name: "LINCE-01", y: 70}, 
 {name: "LINCE-01", y: 155},
 {name: "LINCE-01", y: 210},
 {name: "MIRAFLORES-03", y: 232},
 {name: "MIRAFLORES-03", y: 267}]

Utilizing @VigneshRaja's code snippet:

var result = arr.reduce(function(acc, val){
    var o = acc.filter(function(obj){
        return obj.name==val.name;
    }).pop() || {name:val.name, y:0};

    o.y += val.y;
    acc.push(o);
    return acc;
},[]);

console.log(result);

The initial output was:

result: [{name: "LINCE-01", y: 435},
 {name: "LINCE-01", y: 435},
 {name: "LINCE-01", y: 435},
 {name: "MIRAFLORES-03", y: 499},
 {name: "MIRAFLORES-03", y: 499}]

To remove the duplicates, the following code was employed:

var finalresult = result.filter(function(itm, i, a) {
                            return i == a.indexOf(itm);
                        });
console.log(finalresult);

Ultimately, the desired outcome was achieved:

finalresult = [{name: "LINCE-01", y: 435},
 {name: "MIRAFLORES-03", y: 657}]

Sincerely,

Answer №6

To enhance Mr Nick Parsons' suggestion, I have modified his answer to efficiently calculate the sum of multiple key values.

var data = [{'name':'P1','value':150,'apple':10},{'name':'P1','value':150,'apple':20},{'name':'P2','value':200,'apple':30},{'name':'P3','value':450,'apple':40}];

var result = Object.values(data.reduce((accumulator, {value, apple , ...rest}) => {
  var key = Object.entries(rest).join('-');
  accumulator[key] = (accumulator[key]  || {...rest, apple:0, value: 0});
  return (accumulator[key].apple += apple, accumulator[key].value += value, accumulator);
}, {}));

console.log(result);

Answer №7

Here's another neat solution I came up with:



    var data =  [
        { 'type': 'A', 'amount': 150 },
        { 'type': 'A', 'amount': 150 },
        { 'type': 'B', 'amount': 200 },
        { 'type': 'C', 'amount': 450 }
    ];

     var finalResult = [];
Array.from(new Set(data.map(x => x.type))).forEach(x => {

    finalResult.push(data.filter(y => y.type === x).reduce((output,item) => {
        let val = output[x] === undefined?0:output[x];
        output[x] =  (item.amount +  val); 
       return output;
    },{}));

 })
      
            console.log(finalResult);

If you want to maintain the same object structure, then check this out:

var data =  [
    { 'type': 'A', 'amount': 150 },
    { 'type': 'A', 'amount': 150 },
    { 'type': 'B', 'amount': 200 },
    { 'type': 'B', 'amount': 1000 },
    { 'type': 'C', 'amount': 450 }
];

let resultArray = [];
let finalOutput = {};
let uniqueTypes = Array.from(new Set(data.map(x => x.type)));
uniqueTypes.forEach(n => {
   resultArray.push(data.filter(x => x.type === n).reduce((a, item) => {
      
       let totalAmount = a['type'] === undefined ? item.amount : a['amount'] + item.amount;
        
        return {type:n, amount:totalAmount};
    },{})
);
});

console.log(resultArray);

Answer №8

In comparison to the sample data, my dataset was not as structured. I encountered certain challenges like calculating the total count of unique strings within a group and dealing with surplus data that was irrelevant for the tally.

I also found it tricky to replace some of the demo data object values with actual real-world values while maintaining code readability. Ultimately, I preferred @NickParsons' solution which can be found here: . I chose to enhance this solution further. It crossed my mind whether this enhancement should warrant a new question, more along the lines of "Summing specific keys or strings within arrays," but I felt that elaborating on this post directly was the most appropriate course of action.

After deliberation, I concluded that utilizing Arrays for string manipulation was optimal. I even added an option in my function to de-duplicate arrays if necessary. This way, by using arr.length, the number of hits can be determined. In my scenario, this array could also serve as a collection based on the group category.

Although I anticipate performing additional iterations over my 'Arr_Of_Objs', having this master function allows me to create smaller logical groups of objects. Given the extensive cross-referencing and tallying required, attempting to consolidate all logic into one large iteration proved chaotic quickly.

In addition, I introduced functionality for totaling strings if the object values happen to have a string representation rather than integer values.

Moreover, the capability to pass toFixed for trimming decimal places became part of the feature set.

The inclusion of Criteria_Objs furthers fine-tuning the sums. Since passing an operator isn't supported, I implemented a single if then statement to check for "==" and use == as an operator. If more operators are necessitated, custom coding would be imperative, although integrating them should be straightforward, such as adding >.

Below is a snippet of the code:

 [Code snippet has been omitted for brevity] 

Answer №9

(function () {
var array = [
    {'title': 'Movie1', 'releaseYear': 2021},
    {'title': 'Movie2', 'releaseYear': 2019},
    {'title': 'Movie3', 'releaseYear': 2000}
];
var resultMap = new Map();
var finalResult = [];
arr.map((item) => {
    if (!resultMap.has(item.title))
        resultMap.set(item.title, item.releaseYear);
    else
        resultMap.set(item.title, (item.releaseYear + resultMap.get(item.title)));
})
resultMap.forEach((value, key) => {
    finalResult.push({
        title: key,
        releaseYear: value
    })
})
console.log(finalResult);
})();

Answer №10

let myArray = [
    {
        'id': 'A1',
        'value': 150
    },
    {
        'id': 'A1',
        'value': 150
    },
    {
        'id': 'A2',
        'value': 200
    },
    {
        'id': 'A3',
        'value': 450
    }
]

result array let newDataArray = []

for (let i = 0; i < myArray.length; i++) {
    
        for (let j = i + 1; j < myArray.length; j++) {
    
            if (myArray[j].id == myArray[i].id) {
                console.log('match');
                myArray[i].value += myArray[j].value;
                newDataArray = myArray.filter( element => element !== myArray[j]);
    
                newDataArray = myArray.filter(function (element) {
                    return  element !== myArray[j];
                });
    
            }
        }
    }
console.log(newDataArray)

Answer №11

Could you please offer a more generalized version of the solution for this query?

/**
 * @param {(item: T) => string} keyFn
 * @param {(itemA: T, itemB: T) => T} mergeFn
 * @param {number[]} list
 */
function condenseData(keyFn, mergeFn, list) {
  return Array.from(
    list
      .reduce((map, item) => {
        const key = keyFn(item);

        return map.has(key) // if key already existed
          ? map.set(key, mergeFn(map.get(key), item)) // merge two items together
          : map.set(key, item); // save item in map
      }, new Map())
      .values()
  );
}

const dataToCondense = [
  {
    type: "Type1",
    count: 150,
  },
  {
    type: "Type1",
    count: 150,
  },
  {
    type: "Type2",
    count: 200,
  },
  {
    type: "Type3",
    count: 450,
  },
];

console.log(
  condenseData(
    /* user define which is unique key */
    ({ type }) => type,
    /* how to merge two item together */
    (a, b) => ({ type: a.type, count: a.count + b.count }),
    /* array */
    dataToCondense
  )
)

Answer №12

This method really stands out to me in terms of making the code more readable.

const input = [
  { title: 'Book1', pages: 200 },
  { title: 'Book2', pages: 150 },
  { title: 'Book1', pages: 100 },
  { title: 'Book3', pages: 300 },
];

const result = {};
input.forEach((item) => {
  if (result[item.title]) {
    result[item.title].pages += item.pages;
  } else {
    result[item.title] = item;
  }
});


const summary = Object.values(result);

console.log(input)
console.log(result)
console.log(summary);

Answer №13

Expanding on the original answer, here is a more comprehensive solution for anyone in need:

let dataHolder = {};

data.forEach(entry => {

  if (!dataHolder.hasOwnProperty(entry.name)) {
    dataHolder[entry.name] = { name: entry.name, totalInvested: 0, totalReturned: 0, totalNav: 0, totalIRR: 0 };
  }

  dataHolder[entry.name] = {
    name: entry.name,
    totalInvested: dataHolder[name].totalInvested + entry.invested,
    totalReturned: dataHolder[name].totalReturned + entry.returned,
    totalNav: dataHolder[name].totalNav + entry.nav,
    totalIRR: dataHolder[name].totalIRR + entry.irr,
  };
});

return Object.values(dataHolder);

Answer №14

function filterUniqueItems(items) {
  var uniqueList = [];
  for (let index = 0; index < items.length; index++) {
    const currentItem = items[index];
    const isDuplicate = uniqueList.find(i => i.itemId == currentItem.itemId);
    if (isDuplicate) {
      isDuplicate.quantity = isDuplicate.quantity + currentItem.quantity;
    } else {
      uniqueList.push(currentItem);
    }
  }
  return uniqueList;
}

Answer №15

    An effortless approach to achieve it>
    
    const obj1 = {
  x: 3,
  y: 5,
  };
  
  const obj2 = {
  x: 6,
  y: 2,
  }
  
  function combineObjects(...args) {
  const combined = {};
  
  for (const object of args) {
    for (const key in object) {
      if (!combined[key]) {
      combined[key] = 0;
      }
      combined[key] += object[key];
    }
  }
  
  return combined;
  }
  
  const combinedResult = combineObjects(obj1, obj2);
  console.log(combinedResult);

Answer №16

let array = [
        {'label':'A1','count':100,'banana':15},
        {'label':'A1','count':100,'banana':25},
        {'label':'A2','count':250,'banana':35},
        {'label':'A2','count':700,'banana':35},
        {'label':'A3','count':500,'banana':45}
];

let object = {}

array.forEach((item)=>{
   if(object[item.label]){
        object[item.label].count = object[item.label].count + item.count
   }else{
       object[item.label] = item
   }
})

let updatedArray = Object.values(object)
console.log(updatedArray);

Result

[ { label: "A1", count: 200, banana: 15 },
{ label: "A2", count: 950, banana: 35 },
{ label: "A3", count: 500, banana: 45 } ]

Answer №17

Vignesh Raja's approach demonstrates a useful way to calculate the sum of different values within an array of objects based on their key or other property. This method provides a more efficient solution.

Answer №18

let newData = [
                {
                    'identifier1': 'P1',
                    'value1': 150
                },
                {
                    'identifier1': 'P1',
                    'value1': 150
                },
                {
                    'identifier1': 'P2',
                    'value1': 200
                },
                {
                    'identifier1': 'P3',
                    'value1': 450
                }
            ]
            
             var newArray = []
                        newData.forEach( item => {
                                const existingData = newArray.find( i => i.identifier1 === item.identifier1)
                                if(!existingData){
                                    newArray.push({identifier1: item.identifier1, value1: item.value1})
                                }else{
                                    existingData.value1 = parseInt(existingData.value1) + parseInt(item.value1)
                                }
                        });
            
            console.log(newArray);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Best practices for utilizing child component methods within a parent component in VUE

I am working with the ImageUpload.vue component, which is a straightforward Bootstrap modal containing a few methods. I am currently exploring the best approach to utilize one of these methods. Could it be implemented like this: const app = new Vue({ ...

Extracting data from a nested JSON array within an AngularJS template

Here is some JSON data: { "tracks": [ { "album": { "released": "2013", "href": "spotify:album:3qGeRY1wt4rrLIt1YuSwHR", "name": "The Marshall Mathers LP2 (Deluxe)", "availability": { ...

What could be causing MongoDB to only return the last element in an array when using the find and findOne methods

When I use findOne or find in my mongo cli, why does it only display the last item in the "acts" array? My collection only has one document for testing purposes. This is the code I am running in the mongo shell: db.mycollection.findOne(); The result of f ...

Using Node.js to acquire Steroids.js through downloading

Currently in search of downloading Steroids.js by Appgyver, however I keep encountering an issue: My lack of experience using Node.js makes it difficult to pinpoint the problem, but I suspect it is unrelated to Steroids.js itself. Despite having a version ...

Implement a redux-form within a react-bootstrap modal

I am facing a challenge with incorporating a multipage 'redux-form' form into a react-bootstrap modal. My goal is to have the form displayed within the modal overlay when the modal is opened. How can this be achieved? The code below is producin ...

Generating an Xpath for the selected element with the help of Javascript or Jquery - here's how!

On my website, I have implemented a click event on an element. When a user clicks on this element, I want to generate the XPath of that particular element starting from either the html or body tag, also known as the Absolute Xpath. For example, if I click ...

The response body from the HTTP request is consistently empty or undefined

While working with two containers managed by Docker Compose, I encountered an issue where the response body from a GET call made by a Node.js service in one container to an API in another container using the request module was consistently empty or undefin ...

Does React JS set initial value after re-rendering its state?

Every time the state is updated, the function is triggered once more (please correct me if I am mistaken). And since the initial line of the App function sets the state, the values of data and setData will not revert to their defaults. For instance, i ...

What is the name of the event triggered when a jQuery UI draggable element is reverting back to its original position?

I am currently using jQuery UI to create a draggable element on my website. I have added a function to the drag event that continuously tracks the position of the element while the user is dragging it. Additionally, I have set revert: true on this element ...

Despite calling this.setState to update my state, the render() method is still displaying the previous values

class EditLocation extends Component { constructor(props) { super(); this.state = { LocationId: '', locationOptions: [], } this.baseState = this.state; this.findLocationById = this ...

Having trouble understanding why my submission button isn't working

I'm struggling to understand why my submit button isn't working correctly. Initially, I had an e.preventDefault() at the beginning and it didn't have any effect. However, after receiving advice from an instructor, I included it in the condit ...

Unable to send an API request from Postman to a database through express and mongoose technology

This is my server.js: const express= require('express'); const app = express(); // const mongoose= require('mongoose'); // load config from env file require("dotenv").config(); const PORT = process.env.PORT || 4000; // middl ...

Tips for sending images as properties in an array of objects in React

I've been experimenting with various methods to display a background image underneath the "box" in styled components. How can I pass an image as a prop into the background image of the box with the image stored in the array of objects? I'm unsure ...

Unveiling the Secrets of AJAX Requests with Enigmatic Strings Attached to URLs

My goal is to keep track of cricket scores on scorespro/cricket by utilizing browser AJAX requests. By analyzing the network traffic in Google Chrome, I have noticed that my browser sends out requests in this format: Whenever I click on the response withi ...

The error message "angular is undefined" in Express/AngularJs

Currently, I am following the tutorials on egghead.io with the goal of mastering Angular. However, I am facing some challenges with this particular lesson that covers $http. Despite my efforts, I can't seem to get a basic Expressjs/Angular application ...

Is there a method to determine if a future event has a specific term in its title?

I recently created a script that updates event titles once a user submits a form based on a specific condition: for(var j=0; j<events.length;j++){ var ev = events[j]; if(!ev.getTitle().includes("Returned"){ ... My goal is for ...

Why is it that when drawing rectangles with HTML 5 canvas using pixel size, a black rectangle appears instead of blue?

My intention was to create a large blue rectangle measuring 320 X 240 pixels on the Canvas in Firefox, but I'm only getting a black rectangle instead. This issue is perplexing as I am simply experimenting with pixel drawing and for some reason, it&apo ...

When attempting to insert a date into a MySQL database using React.js, I encountered an issue with the date format

Hey everyone, I have set the input date to dd/mm/yyyy format using moment(donors.donateDate).format('DD-MM-YYYY'). However, when I click the submit button, an error is displayed in the console stating: The specified value "23-03-2022" ...

What is the process for storing arrays with variable-length in C memory?

I've done a lot of research on this topic. From what I've gathered, static arrays are typically stored in a stack and their size is determined at compile time. Ex: int main() { int n; scanf("%d", &n); int array[n]; printf("%u ...

Encountering a 404 Error while using GetStaticPaths in NextJs

Having issues with Next JS dynamic routes resulting in a 404 Error. Initially attempted debugging by setting it up dynamically, then manually at http://localhost:3001/question/62e7b69ca560b1c81aa1a853 but still encountering the same issue. Tried toggling f ...