Use map/reduce to simplify complex array of object

98 Views Asked by At

I'm trying to use reduce to take an array of objects and return an object in below expected format. Able to use it to create object based on validFrom but not able to visulize next steps. Tried to use map as well but didn't helped much. Help would be really appreciated! Can share stackblitz if helps.

Tried this to simplify but got stuck in next step. First comment

inputArray:
[
  {
    "day": "Wednesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Tuesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Sunday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Thursday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Friday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Saturday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Monday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  }
]

Code used:

let clubbedArray = normalData.reduce((acc, temp) => { let { validFrom, day } = temp; return {...acc, [validFrom]: [...(acc[validFrom] || []), day]}; }, {});

Expected Output:

[
  {
    "day": [
      "Friday",
      "Wednesday",
      "Monday",
      "Tuesday",
      "Thursday"
    ],
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": [
      "Saturday",
      "Sunday"
    ],
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  }
]
2

There are 2 best solutions below

1
Yves Kipondo On

You can use Array.prototype.reduce function to change the shape on an array as you want, Here is the code which allow you to change the shape of your data

let data = [
  {
    "day": "Wednesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Tuesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Sunday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Thursday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Friday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Saturday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Monday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  }
];

const result = data.reduce((accumulator, current) => {
   /*
       Check if there is an object on the result array with the corresponding closeTime if that is the case we return it index
   */
   let exists = accumulator.findIndex(item => {
       return item.closeTime == current.closeTime;
   })
   
   // if there is not item with that closeTime the result of the findIndex will be `-1` if so we add an object with the corresponding closeTime with all property of the `current` item of the reduce loop
   if(exists === -1) {
       accumulator = accumulator.concat({
          day: [current.day],
          closeTime: current.closeTime,
          openTime: current.openTime,
          validFrom: current.validFrom,
          validTo: current.validTo,
       })
   } else {
       accumulator[exists].day.push(current.day);
   }
   return accumulator;
}, []);

console.log(result);

1
mandy8055 On

Pseudocode:

1. Use the reduce() method to iterate over the array.
2. Check if the current object matches any of the existing objects in the accumulator array (acc). -- iterate
     2.1. If the properties match: 
         2.1.1. Add the current object's day property to the matching object's day array.
         2.1.1. else, we create a new object with the current object's properties and push it to the acc array.
3. Return the accumulator array.

Implementation:

const normalData = [{
    "day": "Wednesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Tuesday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Sunday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Thursday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Friday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Saturday",
    "closeTime": "1630",
    "openTime": "0845",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  },
  {
    "day": "Monday",
    "closeTime": "2000",
    "openTime": "0800",
    "validFrom": "2001-09-19",
    "validTo": "2099-12-31"
  }
];

const combinedData = normalData.reduce((acc, curr) => {
  let found = false;
  acc.forEach((item) => {
    if (
      item.closeTime === curr.closeTime &&
      item.openTime === curr.openTime &&
      item.validFrom === curr.validFrom &&
      item.validTo === curr.validTo
    ) {
      item.day.push(curr.day);
      found = true;
    }
  });
  if (!found) {
    acc.push({
      day: [curr.day],
      closeTime: curr.closeTime,
      openTime: curr.openTime,
      validFrom: curr.validFrom,
      validTo: curr.validTo,
    });
  }
  return acc;
}, []);

console.log(combinedData);