Ways to combine attributes in an array of objects using a designated property

I am attempting to combine related objects within an array of objects based on matching properties in a specific object key "name".

Although I have implemented the following code, unfortunately it did not yield the desired results:

const students = [];

const obj = [{
    "name": "A. Nasila",
    "adm": "",
    "class": "4p",
    "mat": "80",
    "eng": "",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "4886",
    "class": "",
    "mat": "",
    "eng": "",
    "kis": "39"
  },
  {
    "name": "Mtu Bure",
    "adm": "",
    "class": "3L",
    "mat": "",
    "eng": "86",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "",
    "class": "",
    "mat": "",
    "eng": "75",
    "kis": ""
  },
  {
    "name": "Mtu Bure",
    "adm": "9790",
    "class": "",
    "mat": "77",
    "eng": "",
    "kis": "76"
  }
];

const groupedData = obj.reduce((acc, cur) => {
  const name = cur.name;
  if (!acc[name]) {
    acc[name] = {};
  }

  for (const key in cur) {
    acc[name][key] = cur[key];
  }

  return acc;
}, {});

const result = Object.values(groupedData);

const jsonObject = JSON.stringify(result);

const div = document.getElementById("students");

const span = document.createElement("span");
span.innerHTML = jsonObject;

div.appendChild(span);
<div id="students">
</div>

Please assist me in achieving the expected output as demonstrated below;

[
    {
      "name": "A. Nasila",
      "adm": "4886",
      "class": "4p",
      "mat": "80",
      "eng": "75",
      "kis": "39"
    },
    {
      "name": "Mtu Bure",
      "adm": "9790",
      "class": "3L",
      "mat": "77",
      "eng": "86",
      "kis": "76"
    }
]

Answer №1

Another approach is using the ??= operator (Nullish coalescing assignment)

const data = 
  [ { name: 'A. Nasila', id: '',     group: '4p', math: '80', english: '',   swahili: '' } 
  , { name: 'A. Nasila', id: '4886', group: '',   math: '',   english: '',   swahili: '39' } 
  , { name: 'Random Person',  id: '',     group: '3L', math: '',   english: '86', swahili: '' } 
  , { name: 'A. Nasila', id: '',     group: '',   math: '',   english: '75', swahili: '' } 
  , { name: 'Random Person',  id: '9790', group: '',   math: '77', english: '',   swahili: '76' } 
  ]; 

const result = Object.values(data.reduce((acc, obj) =>
  {
  acc[obj.name] ??= {};
  Object.keys(obj).forEach(key => acc[obj.name][key] ||= obj[key]);
  return acc;
  }, {})); 

console.log( result )
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

Answer №2

This should be functioning properly

const students = [];

const obj = [
  {
    "name": "A. Nasila",
    "adm": "",
    "class": "4p",
    "mat": "80",
    "eng": "",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "4886",
    "class": "",
    "mat": "",
    "eng": "",
    "kis": "39"
  },
  {
    "name": "Mtu Bure",
    "adm": "",
    "class": "3L",
    "mat": "",
    "eng": "86",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "",
    "class": "",
    "mat": "",
    "eng": "75",
    "kis": ""
  },
  {
    "name": "Mtu Bure",
    "adm": "9790",
    "class": "",
    "mat": "77",
    "eng": "",
    "kis": "76"
  }
];

const groupedData = obj.reduce((acc, cur) => {
  const name = cur.name;
  if (!acc[name]) {
    acc[name] = {};
  }

  // Go through the keys of the current object and merge them
  for (const key in cur) {
    if (cur.hasOwnProperty(key)) {
      acc[name][key] = cur[key] || acc[name][key];
    }
  }

  return acc;
}, {});

const result = Object.values(groupedData);

const jsonObject = JSON.stringify(result);

const div = document.getElementById("students");

const span = document.createElement("span");
span.innerHTML = jsonObject;

div.appendChild(span);
<!DOCTYPE html>
<html>
<head>
  <title>Students</title>
</head>
<body>
<div id="students">
</div>

</body>
</html>

A brief explanation of the process

To start with, I utilized the reduce method to loop through the array of objects (obj) and categorize them by the name property into the groupedData object.

If the name property is encountered for the first time, a new object is created for it. If it has been previously encountered, the properties of the current object are merged into the existing object.

The groupedData object was then converted into an array of values using the Object.values method.

EDIT: Adjusted to work dynamically with all keys.

Answer №3

To achieve optimal performance, it is recommended to avoid using spread, intermediate arrays, and retrieving full object data with Object.entries().

Moreover, the behavior in case of two objects containing the same non-empty property is ambiguous. For instance, while I replace it with the latest value, Mr. Jojo prefers to keep the first one.

console.log(
  obj.reduce((r, item, obj) => (
      (obj = r.map.get(item.name)) ? 
      Object.keys(item).forEach(k => k !== 'name' && item[k] && (obj[k] = item[k])) :
      r.map.set(item.name, r.arr[r.arr.length] = item) , r
    ), {arr: [], map: new Map}
  ).arr
);
<script>
const obj = [{
    "name": "A. Nasila",
    "adm": "",
    "class": "4p",
    "mat": "80",
    "eng": "",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "4886",
    "class": "",
    "mat": "",
    "eng": "",
    "kis": "39"
  },
  {
    "name": "Mtu Bure",
    "adm": "",
    "class": "3L",
    "mat": "",
    "eng": "86",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "",
    "class": "",
    "mat": "",
    "eng": "75",
    "kis": ""
  },
  {
    "name": "Mtu Bure",
    "adm": "9790",
    "class": "",
    "mat": "77",
    "eng": "",
    "kis": "76"
  }
];
</script>

Here's a benchmark for comparison:

https://i.sstatic.net/kX9ZM.png

<script benchmark data-count="1000000">

const obj = [{
    "name": "A. Nasila",
    "adm": "",
    "class": "4p",
    "mat": "80",
    "eng": "",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "4886",
    "class": "",
    "mat": "",
    "eng": "",
    "kis": "39"
  },
  {
    "name": "Mtu Bure",
    "adm": "",
    "class": "3L",
    "mat": "",
    "eng": "86",
    "kis": ""
  },
  {
    "name": "A. Nasila",
    "adm": "",
    "class": "",
    "mat": "",
    "eng": "75",
    "kis": ""
  },
  {
    "name": "Mtu Bure",
    "adm": "9790",
    "class": "",
    "mat": "77",
    "eng": "",
    "kis": "76"
  }
];

// @benchmark Jojo

Object.values(obj.reduce((r,o) =>
  {
  r[o.name] ??= {};
  Object.keys(o).forEach(k => r[o.name][k] ||= o[k]);
  return r;
  },{})); 

// @benchmark Alexander

 obj.reduce((r, item, obj) => {
          (obj = r.map.get(item.name)) ? 
          Object.keys(item).forEach(k => k !== 'name' && item[k] && (obj[k] = item[k])) :
          r.map.set(item.name, r.arr[r.arr.length] = item);
          return r;
        }, {arr: [], map: new Map}
      ).arr

</script>

<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>

Answer №4

Is there a way to efficiently loop through the code within if & else statements? It seems cumbersome to utilize it on an object with numerous keys.

  • If the keys will always be the same, consider hardcoding them into a list.
  • If you can assume the keys will remain consistent within the array but cannot be hardcoded, try using Object.keys() on the first object.

You can then create an object from an array of [key, value] pairs using Object.fromEntries().

Be cautious when handling values containing falsy values like empty strings as you cannot use the ?? operator.

const keys = Object.keys(obj[0])

const result = Object.values(
  obj.reduce(
    (acc, curr) => ({
      ...acc,
      [curr.name]: Object.fromEntries(
        keys.map((key) => [key, curr[key] || acc[curr.name]?.[key]])
      ),
    }),
    {}
  )
)

PS: While other solutions may offer better performance, unless this code is in a critical path of your application, prioritize readability over optimization.

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

Executing a JavaScript function once an iframe has finished loading

I currently have this code on my index.html file: <body> <iframe id=iframetest src="alt.html"> <p>Your browser does not support iframes.</p> </iframe> <script> $(window).load(function(){ ...

A step-by-step guide on duplicating the functionality of the jQuery

Issue at Hand: I'm attempting to recreate the functionality of jQuery's ajax method as I find myself utilizing XMLHttpRequest multiple times within a script. However, I am hesitant to include jQuery as a dependency since I only require a few meth ...

Creating a chart with multiple series in canvas js through looping

I'm currently working on creating a multi-series chart using Canvasjs. I've encountered an issue where I can't include a loop inside the dataPoints and have had to manually code everything. Is there a way to utilize for loops in this scenari ...

What is the method for inserting form control values into a QueryString within HTML code?

Struggling with passing HTML form control values into a QueryString for page redirection. While I can easily input static values into a QueryString and retrieve them using PHP's GET method, I am encountering difficulties when it comes to dynamic valu ...

Is it recommended to utilize AJAX throughout an entire website for optimal performance?

I have a unique template structure where a single HTML file loads related HTML & JS files using AJAX. Sections are loaded based on the user's activity, without the page ever reloading, creating a smooth user experience. For example, when a user clic ...

JavaScript's Ajax POST request to PHP is not functioning as expected

My current code setup involves handling $_GET[] requests on the products.php page by passing them to get_data_products.php via an ajax POST request. The data retrieved from get_data_products.php is then displayed accordingly. PHP if(isset($_GET['cat ...

In Nodejs, there is a way to determine the size of a document stored

I have a question: How can I determine the size of a cursor, in terms of kilobytes (KB), without actually fetching it? I've come across various sources, such as this post on Stack Overflow, but I don't want to retrieve the query result just to f ...

Fix a carousel layout problem

I've made changes to an HTML-PHP module to display portfolio images as a carousel, and I'm using the same module on this website too. However, I've encountered an issue with duplicate content and the previous-next navigation buttons. Can so ...

Why is my output getting mixed up with the header on the navigation bar page?

output capture image https://i.sstatic.net/BYJnk.jpg here is the code snippet //ui.r library(shiny) navbarPage(theme = "style.css",img(src="logo.jpeg", width="300px"), tabPanel("Dashboard"), tabPanel("Products"), tags$head( t ...

Dynamic computed subcomponents in Vue.js are a powerful way to create flexible

Currently, I am facing a scenario where I need to create computed local subcomponents. Specifically, I am working on custom data grid row cell components. Here is an example of what I am trying to achieve: var DataGridRow = { props: ['columns&ap ...

Manipulate objects in three.js to always face the mouse pointer

It seems that despite my efforts, I am struggling with this task as I am relatively new to it. Surprisingly, I am not getting any errors in Dreamweaver. I've started fresh by integrating the look at function with the OBJ loader, camera, and lights in ...

Visualize dynamic information from MySQL using Highcharts

After discovering a live data example in Highcharts here, I decided to personalize it with my own MySQL data. To achieve this, I made adjustments to the $y variable in live-server-data.php by utilizing the fetch_assoc() function. Customized HTML Code < ...

Consistently Incorrect Date Formatting in Bootstrap Display

I have a potential issue with my date display. It should show a default "Start Date" in a short date format, but when the "Sale Date" DropDownBoxFor is toggled, it should display an AJAX result date. However, the display always appears in a date and time f ...

Display database items in ng-repeat in reverse order

In my MongoDB database, there is an 'photos' array that gets updated whenever users upload new pictures from Instagram at specific locations. Each time a new photo is added, it goes to the end of the array. However, this is causing a problem for ...

Tips for retrieving JSON-formatted data from an API in Python and saving it to a .db file

I need assistance with fetching data from an API in JSON format at this URL using Python. I aim to create a table filled with the retrieved data and then perform SQL queries on it using sqlite3 by pushing the data to my database named pitch.db. Below is t ...

Instructions for displaying typed chat messages on the screen using socket.io and node.js

I am currently developing a chat application using socket.io and node.js. I have successfully connected the server and both the socket.io and client-side socket.io are also connected. However, when I type a message on the localhost page and hit enter, noth ...

JavaScript stylesheet library

What is the top choice for an open-source JavaScript CSS framework to use? ...

Moshi: The process of transforming JSON data into a Java object, specifically when dealing with a class that includes a List<Object> field

Imagine a scenario where you have the following setup: public class Container implements Serializable { private List<Object> elements; [... some other fields ...] } public class A implements Serializable { ... } public class B implemen ...

Logo remains in place when scrolling halfway down the page

I have a logo that I want to stay halfway up the home page when scrolling, as if fixed in place until it reaches the footer. body { background-color: #fff; margin: 0; } nav { position: sticky; top: 0; width: 300px; height: 80px; margin:4 ...

What is the process for transferring a Python variable to JavaScript when the Python code is a cgi script?

I am currently working on a JavaScript file where I am attempting to assign a variable based on data received from a Python CGI script. My approach involves using the Ajax GET method to retrieve the data and set the variable within that method. Below is a ...