Array of objects manipulation

419 views Asked by At

I feel that im close to the answer but I am not outputting exactly the format Im looking for

So, I have this array of objects:

const data = [
{email: '[email protected]', amount: '30', date: '2018-12'},
{email: '[email protected]', amount: '30', date: '2018-11'},
{email: '[email protected]', amount: '30', date: '2018-10'},

{email: '[email protected]', amount: 0,    date: '2018-12'},
{email: '[email protected]', amount:'30',  date: '2018-11'},
{email: '[email protected]', amount:'30',  date: '2018-10'},
{email: '[email protected]', amount:'30',  date: '2018-09'},
{email: '[email protected]', amount:'25',  date: '2018-08'},
{email: '[email protected]', amount:'25',  date: '2018-08'},]

As you can see in the data set there are repeated emails as well as duplicate objects like the last 2 in the data set.

I want to turn it into this array of objects:

const data = [
{
    email: '[email protected]',
    '2018-12': '30',
    '2018-11': '30',
    '2018-10': '30', 
    '2018-09': 0, 
    '2018-08': 0, 
    '2018-07': 0, 
    '2018-06': 0, 
    '2018-05': 0, 
    '2018-04': 0, 
    '2018-03': 0, 
    '2018-02': 0, 
    '2018-01': 0, 
    '2017-12': 0, 
},
{
    email: '[email protected]',
    '2018-12':0,
    '2018-11':'30',
    '2018-10':'30',
    '2018-09':'30',
    '2018-08':'25',
    '2018-07': 0,
    '2018-06': 0,
    '2018-05': 0,
    '2018-04': 0,
    '2018-03': 0,
    '2018-02': 0,
    '2018-01': 0,
    '2017-12': 0,
}]

The output has a range of dates from 2017-12 to 2018-12 and the value for the date key is the amount for that specific date, else if the date is not found on the object the value for that date defaults to 0

At the moment Im playing with the reduce() function using something like this:

let result = data.reduce((acc, {email, date, amount}) => {
    acc.email = email
    acc[date] = amount
    return acc;
}, {});

result is only returning the last email with not exactly the range of dates Im looking for.

Thanks in advance for your help.

2

There are 2 answers

0
CertainPerformance On BEST ANSWER

Reduce into an object indexed by each email, creating the inner object explicitly if the [email] property doesn't exist on the accumulator yet. Once you're sure the object exists, you can assign to acc[email][date], and at the end, use Object.values to transform the object back into the desired array format:

const data = [
{email: '[email protected]', amount: '30', date: '2018-12'},
{email: '[email protected]', amount: '30', date: '2018-11'},
{email: '[email protected]', amount: '30', date: '2018-10'},

{email: '[email protected]', amount: 0,    date: '2018-12'},
{email: '[email protected]', amount:'30',  date: '2018-11'},
{email: '[email protected]', amount:'30',  date: '2018-10'},
{email: '[email protected]', amount:'30',  date: '2018-09'},
{email: '[email protected]', amount:'25',  date: '2018-08'},
{email: '[email protected]', amount:'25',  date: '2018-08'},]

let result = data.reduce((acc, {email, date, amount}) => {
  if (!acc[email]) acc[email] = { email };
  acc[email][date] = amount;
  return acc;
}, {});
console.log(Object.values(result));

0
Drew Reese On

const data = [
  {email: '[email protected]', amount: '30', date: '2018-12'},
  {email: '[email protected]', amount: '30', date: '2018-11'},
  {email: '[email protected]', amount: '30', date: '2018-10'},
  {email: '[email protected]', amount: 0,    date: '2018-12'},
  {email: '[email protected]', amount:'30',  date: '2018-11'},
  {email: '[email protected]', amount:'30',  date: '2018-10'},
  {email: '[email protected]', amount:'30',  date: '2018-09'},
  {email: '[email protected]', amount:'25',  date: '2018-08'},
  {email: '[email protected]', amount:'25',  date: '2018-08'},
];

/*
  Reduce into an object with email as key and email 
  and date/amount(s) as value, wrapped in Object.values 
  to return the array of augmented data values.
*/
augmentData = (data) => Object.values(
  data.reduce((acc, {email, amount, date}) => {
    (acc[email] || (acc[email] = {email}))[date] = amount;
    return acc;
  }, {})
);

/*
  Reduce straight to array of augmented data 
  objects containing email and date/amount values.
*/
augmentData2 = data => data.reduce((acc, {email, amount, date}) => {
  const findEl = (arr) => arr.find(el => el.email == email);
  const createEl = (arr, email) => arr.push({email}) && findEl(arr);
  
  (findEl(acc) || createEl(acc, email))[date] = amount;
  return acc;
}, []);

const augmentedData = augmentData(data);
console.log('augmentedData', augmentedData);

const augmentedData2 = augmentData2(data);
console.log('augmentedData2', augmentedData2);