Summarize the array of objects and find the average value for each distinct object name

I'm facing a challenge with an array structure:

const originalArray = [
     {
       name: "a",
       value: 1 
     },
     {
       name: "a",
       value: 2 
     },
     {
       name: "a",
       value: 3 
     },
     {
       name: "b",
       value: 0 
     },
     {
       name: "b",
       value: 1 
     }
 ];

My goal is to transform this array into the following format:

const newArray = [
     {
       name: "a",
       value: 2
     },
     {
       name: "b",
       value: 0.5
     }
 ]

The new array should contain each unique name as an object with the average value.

Any suggestions on how to achieve this efficiently?

Answer №1

To find the average of values in an array, you will need to iterate through the array and calculate the sum as well as the count for each object. Here is a simple example:

function calculateAverage(array) {
    var sums = {}, counts = {}, results = [], name;
    for (var index = 0; index < array.length; index++) {
        name = array[index].name;
        if (!(name in sums)) {
            sums[name] = 0;
            counts[name] = 0;
        }
        sums[name] += array[index].value;
        counts[name]++;
    }

    for(name in sums) {
        results.push({ name: name, value: sums[name] / counts[name] });
    }
    return results;
}

See it in action

Alternatively, using a library like Underscore.js can simplify this process:

var averages = _.chain(array)
                .groupBy('name')
                .map(function(group, key) {
                    return { 
                        name: key, 
                        value: _.chain(group)
                                .pluck('value')
                                .reduce(function(x, y) { return x + y })
                                .value() / group.length
                    };
                })
                .value();

Check out the demo

Answer №2

let data = [
     {
       title: "apple",
       quantity: 1 
     },
     {
       title: "apple",
       quantity: 2 
     },
     {
       title: "apple",
       quantity: 3 
     },
     {
       title: "banana",
       quantity: 0 
     },
     {
       title: "banana",
       quantity: 1 
     }
 ];
let summary = {};
for(let i = 0; i < data.length; i++) {
    let element = data[i];
    if (!summary[element.title]) {
        summary[element.title] = {};
        summary[element.title]["total"] = 0;
        summary[element.title]["count"] = 0;
    }
    summary[element.title]["total"] += element.quantity;
    summary[element.title]["count"]++;
}
let finalResult = [];
for (let title in summary) {
    finalResult.push({title: title, quantity: summary[title]["total"] / summary[title]["count"]});
}
console.log(finalResult);

Answer №3

Transforming your data can be easily accomplished using the Alasql library in just one line of code:

var modifiedArray = alasql('SELECT name, AVG([number]) AS [number] FROM ? GROUP BY name',
                       [data]);

I opted to enclose "number" in square brackets to avoid conflicts with SQL keywords.

Feel free to experiment with this live example on jsFiddle

Answer №4

Check out this ES2015 implementation that utilizes the reduce function:

const data = [
  { x: 1, y: 1 },
  { x: 2, y: 3 },
  { x: 6, y: 4 },
  { x: 2, y: 1 },
  { x: 8, y: 2 },
  { x: 0, y: 2 },
  { x: 4, y: 3 }
]

const result = data.reduce((prev, curr, index, arr) => {
    const keys = Object.keys(prev)
    let obj = {} 

    keys.map((key) => {
        obj[key] = prev[key] + curr[key]

        if (index + 1 === arr.length) {
            obj[key] = obj[key] / arr.length
        }
    })

    return obj
})

Answer №5

One potential solution utilizing ECMA5 (which appears to be missing)

var sums = {},
    averages = Object.keys(array.reduce(function (previous, element) {
        if (previous.hasOwnProperty(element.name)) {
            previous[element.name].value += element.value;
            previous[element.name].count += 1;
        } else {
            previous[element.name] = {
                value: element.value,
                count: 1
            };
        }

        return previous;
    }, sums)).map(function (name) {
        return {
            name: name,
            average: this[name].value / this[name].count
        };
    }, sums);

Check out the code on jsFiddle

Answer №6

In the month of October 2020, here is a concise solution using ES6+

const calculateAverageByCategory = (dataArr, categoryKey, valueKey) => {
  const calculateAvg = (accumulator, currentValue, index, array) => accumulator + currentValue[valueKey] / array.length;
  return Object.values(
    dataArr.reduce((acc, element, index, inputArray) => (
        (acc[element[categoryKey]] = acc[element[categoryKey]] || {
          [categoryKey]: element[categoryKey],
          [valueKey]: inputArray.filter((x) => x[categoryKey] === element[categoryKey]).reduce(calculateAvg, 0),
        }),acc),{})
  );
};

console.log(calculateAverageByCategory(dataArray, 'group', 'amount'))

Give it a try on your own :)

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

Is it possible to store input from a multiline TextArea into an array using NetBeans?

I'm currently working on a task that involves taking a list of names from a multiline TextArea, putting them into an array, making some modifications, and then displaying them in a list. However, I've encountered an issue with extracting the inp ...

Selenium Python option other than using send_keys()

I was looking to enhance the efficiency of this Python code and found a faster alternative: driver.get(myUrl) message = driver.find_element_by_id('message') send = driver.find_element_by_id('submit') for _ in range(myRange): messa ...

What is the reason behind the perpetual hiding of the button?

<div class="app__land-bottom" v-if="isVisible"> <a href="#projects"> <img ref="arrowRef" id="arrow" src="./../assets/down.png" alt srcset /> </a> </div> When ...

Difficulty loading AJAX with autocomplete feature. Any suggestions?

I have created a jQuery autocomplete feature that works correctly, but when the value is removed using the Backspace key, the 'LOADING...' message remains visible instead of hiding. How can I make it so that after removing the value with the Back ...

What is the best way to display three unique maps simultaneously on separate views?

In this scenario, I have incorporated three separate divs and my goal is to integrate three maps into them. The javascript function that controls this process is as follows: function initialize() { var map_canvas1 = document.getElementById('map_canva ...

Creating Event Handlers for corresponding elements in HTML with the help of JQuery and JavaScript

Struggling with HTML and debugging an issue in my ASP.NET Core App. The problem lies in a CSHTML view that functions as a timeclock system for tracking user input against job numbers. The current Index.cshtml is operational, verifying JobNumbers against t ...

Refreshing user session with the help of selenium's webdriver functionality

Our application requires some external inputs for testing purposes, but this data is only accessible when a user is logged in. To streamline the process and avoid requiring the user to log in multiple times, we store their credentials in a session upon ini ...

Animating Divs with jQuery to Expand their Size

I am currently designing a services page for my portfolio website. The layout consists of three columns, with the central column containing a large box and the left and right columns each containing three smaller boxes. These smaller boxes function as clic ...

Reopen a Kendo UI dialog

Currently, I am utilizing Kendo UI, and my goal is to display a modal dialog when a button is clicked. The issue I am facing is that it works perfectly the first time around. However, upon closing the dialog and attempting to reopen it by clicking the butt ...

Struggling to get Axios working in Node despite having it properly installed

I am encountering an issue with my Jasmine test that involves HTTP requests. Despite having Axios installed using the command npm install axios --save, I keep getting the error message axios is not defined. var request = require('axios'); var co ...

What is the best way to create a time delay between two consecutive desktop screenshot captures?

screenshot-desktop is a unique npm API that captures desktop screenshots and saves them upon request. However, I encounter the need to call the function three times with a 5-second delay between each call. Since this API works on promises, the calls are e ...

ngDraggable does not function properly when the dropzone is larger and includes a scrollbar on the body

Here is a demo showing the issue: The current version 0.1.11 does not support drag and drop functionality. This is how I have implemented the code: <uib-accordion-group is-open="category.open" name="category-{ ...

Transforming numbers into arrays in JavaScript/TypeScript for Angular 7

What is the best way to convert the number 10 into an array in JavaScript? expected output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] OR How can I transform the number 10 into the number of items within an array using JavaScript? ...

Problem encountered with @HostListener

In an Angular component, I have the following code snippet that is functioning as intended: @HostListener('document:click', ['$event']) onClick(event) { if(!this.eRef.nativeElement.contains(event.target)) { console.log("clicked out ...

How can I use jQuery to switch the positions of two <div> elements in HTML based on the selection of a dropdown value?

I need to switch the display positions of two <div> containers based on a dropdown value change. Can this be accomplished using jQuery? Here are the two div containers whose display positions need to be interchanged: <div id="first"><p> ...

Converting a Javascript string to 'Title Case' does not yield any results

I'm having trouble identifying the bug in this code as it's not generating any output: function convertToTitleCase (inputString) { var wordArray = inputString.split(' '); var outputArray = []; for (var j = 0; j ...

The following middleware is not functioning properly on a local SSL server

When I run my Nextjs app without SSL using "next dev", the middleware functions as expected without any errors. However, if I attempt to run the app with SSL enabled, an empty middleware function triggers an error. The code for the middleware function (l ...

Creating a reverse proxy using next.js

My goal is to set up a reverse proxy for the GeForce NOW website using Next.js, but I'm struggling to make it work. module.exports = { async rewrites() { return [ { source: '/:slug', destination: 'https://pla ...

How can I incorporate popups in React using mapbox-gl?

Currently utilizing mapbox-gl within React, everything seems to be functioning properly except for the integration of mapbox-gl's Popups. I have the function let Popup, but I am uncertain about how to incorporate it. renderMap() { if (this.props. ...

Is it possible to customize the appearance of the selected item in a select box? Can the selected value be displayed differently from the other options?

My current project involves working with the antd' select box. I have been trying to customize the content inside the Option which usually contains regular text by incorporating some JSX into it. The output currently looks like this: I have also crea ...