Using reduce() to group items in an array based on a specific object property

Creating a new array grouped by the property 'desc' of the objects within an existing array is my current task. Here is how I envision it:

const sourceArray = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const targetArray = [
  { desc: 'foo', ids: [
    { id: 'id1', prop1: 'ignoreme', prop2: 'ignoreme' },
    { id: 'id2', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]},
  { desc: 'bar', ids: [
    { id: 'id3', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]},
  { desc: 'baz', ids: [
    { id: 'id4', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]}
];

I believe using the reduce() higher-order function would be the most efficient way to accomplish this. However, I am facing some challenges in adapting the solutions I've found to fit my array structure. Any guidance on how to approach this would be greatly appreciated!

Answer №1

One way to achieve the desired result is by leveraging the power of the .reduce() and .find() methods together:

const inputData = [
  { id: 'id1', dataKey: 'valueA', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', dataKey: 'valueA', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', dataKey: 'valueB', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', dataKey: 'valueC', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const processedData = inputData.reduce((accumulator, currentElement) => {
  const foundElement = accumulator.find(item => item.key === currentElement.dataKey);
  
  if (foundElement) foundElement.ids.push({
    id: currentElement.id,
    prop1: currentElement.prop1,
    prop2: currentElement.prop2
  });
  else accumulator.push({
    key: currentElement.dataKey,
    ids: [{
      id: currentElement.id,
      prop1: currentElement.prop1,
      prop2: currentElement.prop2
    }]
  });
  return accumulator;
}, []);

console.log(processedData);

Answer №2

To achieve the desired result, you can utilize the .reduce() method in combination with Object.entries() and .map() methods:

const data = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const reducer = (arr) => Object.entries(
  arr.reduce((r, { sourceDesc:desc, ...rest }) => {
    r[desc] = r[desc] || [];
    r[desc].push(rest);
    return r;
  }, {})
).map(([k, v]) => ({desc: k, ids: v}));

console.log(reducer(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №3

One way to utilize reduce is demonstrated below:

const data = [
  { id: 'id1', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { id: 'id2', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { id: 'id3', 'sourceDesc': 'bar', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { 'id': 'id4', 'sourceDesc': 'baz', 'prop1': 'ignoreme', 'prop2': 'ignoreme' }
];

const result = data.reduce((output,{id,sourceDesc,prop1,prop2})=>{
  let key = sourceDesc;
  output[key] = output[key] || {des:sourceDesc, ids:[]};
  output[key].ids.push({id,prop1,prop2});
  return output;
},{});

console.log(Object.values(result));

Answer №4

To transform the array into a Map structure, utilize the sourceDesc as the key and then expand the Map.values() iterator to convert it back into an array:

const sourceArray = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const result = [...
  sourceArray.reduce((r, { sourceDesc: desc, ...o }) => {
    if(!r.has(desc)) r.set(desc, { desc, ids: [] }); 

    r.get(desc).ids.push(o); 

    return r;
  }, new Map)
.values()]; 

console.log(result);

Answer №5

Check out this alternative method for grouping JSON arrays by key using the map function:

const inputArray = [{"id":"id1","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id2","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id3","sourceDesc":"bar","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id4","sourceDesc":"baz","prop1":"ignoreme","prop2":"ignoreme"}];

const targetKey = 'sourceDesc';

const groupedArray = [...new Map(inputArray.map(item =>
  [item[targetKey], inputArray.filter(x=>x[targetKey] == item[targetKey])]))
 /*uncomment to flatten array*/ //.values()
];

console.log(groupedArray);

   /*EXPECTED OUTPUT
       [
  [
    "foo",
    [
      {
        "id": "id1",
        "sourceDesc": "foo",
        "prop1": "ignoreme",
        "prop2": "ignoreme"
      },
      {
        "id": "id2",
        "sourceDesc": "foo",
        "prop1": "ignoreme",
        "prop2": "ignoreme"
      }
    ]
  ]
]
   */

Answer №6

To achieve this, we can utilize the forEach method and create an object with keys corresponding to the values of sourceDesc.

const sourceArray = [
  { id: "id1", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id2", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id3", sourceDesc: "bar", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id4", sourceDesc: "baz", prop1: "ignoreme", prop2: "ignoreme" }
];

const update = data => {
  const res = {};
  data.forEach(({ sourceDesc, ...item }) => {
    if (!res[sourceDesc]) {
      res[sourceDesc] = { desc: sourceDesc, ids: [] };
    }
    res[sourceDesc].ids.push(item);
  });
  return Object.values(res);
};

console.log(update(sourceArray));

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

Unable to alter the background color in a table row when a condition is verified

Within my 'work' array that is generated from an Excel file, I have values for employee_id (referred to as id), projects, and hours. Additionally, I have another array called 'employees' which contains all the employees in my database. ...

What is the method for modifying the array that has been generated using Vue's "prop" feature?

According to the Vue documentation, a prop is passed in as a raw value that may need transformation. The recommended approach is to define a computed property using the prop's value. If the "prop" is an array of objects, how can it be transformed int ...

Every time I click a button, I am trying to add JSON objects into an array and then show the outcomes

Currently, my goal is to create a random selection feature from an array that users can contribute to by clicking a button. I am a bit unsure about how to proceed with this task. The application is developed in React and it utilizes the movieDB's API ...

Is there a way for me to determine the quality of a video and learn how to adjust it?

(function(){ var url = "http://dash.edgesuite.net/envivio/Envivio-dash2/manifest.mpd"; var player = dashjs.MediaPlayer().create(); player.initialize(document.querySelector("#videoPlayer"), url, })(); var bitrates = player.getBitrateInfoListFor("vid ...

Convert the data received from jQuery $.parseJSON into HTML code

I am using $.parseJSON to retrieve data from a specific URL. The link I receive contains {"status":"ok", "message":'<form><input type="text" name="" value=""> </form>'} Now, I want to add the "message" part to my content. $. ...

JavaScript - the global and local variable dilemma

REVISED2: I'm encountering an issue with converting images to canvas using Pixastic in HTML5. How can I 'return' this converted image back to a global variable? Any suggestions? <img id="mainIllustration" alt="main illustration" src="Img ...

Is there a way to shift a background image pattern?

After searching extensively, I came up empty-handed and am seeking guidance on how to achieve a specific effect. Specifically, I am in need of a JavaScript or jQuery script that can smoothly shift a background image to the right within a designated div con ...

Tips for accessing the next sequential tag that is similar in HTML with the help of jQuery

I have generated the following HTML code from some plugins. <div class="parent"> <span>item1</span> <input type="hidden"></input> <span>item2</span> <span class="active">item3</span> <inpu ...

Troubleshooting Problem with Scrolling Sticky Element on iOS Devices

This is specifically for mobile devices I am facing an issue with a relative positioned element where it should become fixed to the top of the screen when the scroll position exceeds the top position of the element. However, in iOS, when scrolling, the f ...

Navigating the loop in Vue using JavaScript

I'm facing an issue where I need to send data at once, but whenever I try sending it in a loop, I end up getting 500 duplicate id status errors. I have a hunch that if I click on something in JavaScript, the data might be sent all at once. assignment ...

Get a file from a node.js web server by clicking a button to initiate the download

I am a beginner in nodejs and I am working on creating a web server using nodejs to host some static files. Here is the code I have used for this purpose: var http = require('http'); var finalhandler = require('finalhandler'); var ser ...

What is the process for retrieving the chosen country code using material-ui-phone-number?

When incorporating user input for phone numbers, I have opted to utilize a package titled material-ui-phone-number. However, the challenge arises when attempting to retrieve the country code to verify if the user has included a 0 after the code. This infor ...

What are the steps to designing a unique JSON data format?

When working with a JSON data structure containing 100 objects, the output will resemble the following: [{ "Value": "Sens1_001", "Parent": Null, "Child": { "Value": "Sens2_068", "Parent":"Sens1_001", "Child" : { ...

conceal the .card-body element if the children have the CSS property "display:none"

My challenge involves managing two collapsible cards on a webpage. I am looking for a solution where the .card-body will have its display set to none when there are no inner divs to show in the card upon clicking a letter in the pagination. Otherwise, the ...

What causes Vue to only update once when there are two closely timed mutations to reactive data?

Can you take a look at this simple example? export default { data() { return { name: "Amy", age: 18, }; }, computed: { combinedDataForWatching() { return { name: this.name, age: this.age, ...

Ensure all asynchronous Ajax requests have completed before considering the page fully loaded

Many websites, such as YouTube, load the majority of their content after the DOM is ready using JavaScript. How can I ensure that all of these requests have been completed before injecting my code? window.onload = function() {}; The above code snippet do ...

Difficulty in toggling on and off several form elements with JavaScript

Trying to control multiple form elements on an HTML page with JavaScript has presented a challenge for me. In my form, each row contains a checkbox that should enable/disable the elements on that row. The issue I'm facing is that only the first two f ...

What are some methods for transferring the state variable's value from one component to another in React?

I have the following scenario in my code: there is a Form.js component that interacts with an API, stores the response in the walletAssets state variable, and now I want to create a separate Display.js component to present this data. How can I pass the v ...

Is there a method to retrieve a value from a node.js server when a div is clicked?

This is the EJS file I've created: <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Sart Plug</title> <script src="http://code.jquer ...

Using JavaScript and Ruby on Rails to dynamically modify URL query parameters based on a dropdown form

I need help updating a URL based on dropdown selection. I want the query to be dynamic, and here is my current code snippet: <select id="mySchool" onchange="this.form.submit()"> <% @schools.each do |school| %> <option value="< ...