Search code examples
javascriptarraysjavascript-objectsreduce

Creating a reduce method that can handle any number of objects with unique Ids


I am trying to use the reduce method to sort through an array of objects. My goal is to create a reduce method that can handle any number of objects (with unique eventIds). The desired output would be formatted like this but with the capability to handle more than just five unique eventIds

[Desired Output]

     (5) [{…}, {…}, {…}, {…}, {…}]
       0:
          eventId: "12345"
          total: Array(3)
            0: {total: 123}
            1: {total: 45}
            2: {total: 123}
            length: 3

       1: {total: Array(3), eventId: '12347'}
       2: {total: Array(3), eventId: '12349'}
       3: {total: Array(3), eventId: '12348'}
       4: {total: Array(3), eventId: '12346'}

To get the output above I used this reduce method.

[Reduce Method]

      const sortedSalesData = salesData.reduce((acc, obj) => {

      for ( let i = 0; i<salesData.length; i++) {

        if (obj.eventId === salesData[i].eventId ) {

          acc[i].eventId = salesData[i].eventId;
          acc[i].total = [...acc[i].total, {total: obj.total}];

          return acc;
        }
      };
      
  },[{total:[]},{total:[]},{total:[]},{total:[]},{total:[]}]);  

But I'm not sure how to set it up to handle more than those five unique eventIds. Below is the original array for reference.

[Original Array]

    const salesData = 
    [
      { eventId: '12345', total: 123 },
      { eventId: '12347', total: 45 },
      { eventId: '12349', total: 78 },
      { eventId: '12348', total: 123 },
      { eventId: '12346', total: 45 },
      { eventId: '12349', total: 78 },
      { eventId: '12347', total: 123 },
      { eventId: '12345', total: 45 },
      { eventId: '12348', total: 78 },
      { eventId: '12345', total: 123 },
      { eventId: '12347', total: 45 },
      { eventId: '12346', total: 78 },
      { eventId: '12349', total: 123 },
      { eventId: '12348', total: 45 },
      { eventId: '12346', total: 78 },
     ];     

The hangup is getting it to a place where it can handle any number of unique events without having to add an additional {total:[]} at the end of the method.


Solution

  • You wan t to iterate over the initial array (obj), insert the iterated element on a new array (acc) if eventId doesn't exist yet on said array, when it does exist (accObj), you want to push the total object of the current element (obj) onto the total array of the new element (accObj)?

    I think this does what you need:

    let array = [
      { eventId: '12345', total: 123 },
      { eventId: '12347', total: 45 },
      { eventId: '12349', total: 78 },
      { eventId: '12348', total: 123 },
      { eventId: '12346', total: 45 },
      { eventId: '12349', total: 78 },
      { eventId: '12347', total: 123 },
      { eventId: '12345', total: 45 },
      { eventId: '12348', total: 78 },
      { eventId: '12345', total: 123 },
      { eventId: '12347', total: 45 },
      { eventId: '12346', total: 78 },
      { eventId: '12349', total: 123 },
      { eventId: '12348', total: 45 },
      { eventId: '12346', total: 78 },
    ]
    
    let reducedArray = array.reduce((acc, obj) => {
      console.log("Element " + JSON.stringify(obj));
      let accObj = acc.find(accObj => accObj.eventId === obj.eventId);
      if(accObj != undefined) {
        console.log("Found element: " + JSON.stringify(accObj) + ".")
        console.log("Pushing "+ obj.total +" to total.")
        accObj.total.push(obj.total);
      } else {
        accObj = { eventId: obj.eventId, total: [obj.total] };
        console.log("Pushing new element to list: " + JSON.stringify(accObj));
        acc.push(accObj);
      }
      return acc;
    }, []);
    
    console.log(JSON.stringify(reducedArray));

    The trick is on the find method, I'm searching my own reducing list to see if it already has an element that shares eventId with the old array.