Y_Lakdime
Y_Lakdime

Reputation: 825

Group array objects by two elements and sum values (Javascript)

I have the following case:

I have an array consisting of all the appointments of the currently logged in user, like this:

 this.appointments = [  
{ 
 CreatedBy: "bob",
 Description: "smthng",
 EndTime: "2020-06-01T17:00:00.000Z",
 EndTimezone: null,
 Id: 3,
 IsAllDay: false,
 Client: "Steven",
 Location: "smthng",
 RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
 StartTime: "2020-06-01T09:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng",
 km: 88,
 week: 23,
 _id: "5ecc6f4a08c79c6328974699"
}, 
{ 
 CreatedBy: "bob",
 Description: "smthng",
 EndTime: "2020-06-08T10:30:00.000Z",
 EndTimezone: null,
 Id: 4,
 IsAllDay: false,
 Client: "Steven",
 Location: "smthng",
 RecurrenceRule: null,
 StartTime: "2020-06-08T10:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng"  ,
 km: 88,
 week: 24,
 _id: "5ed450d299d5303bd0338a7f"
}
  ] 

What I ultimately want to do is group the array by Client per Week. So accumulate all the time and km of the appointments (using dayjs library) of one week per client. This is the .reduce function I have now which groups the array only by Client but not yet per week:

this.appointments.reduce(function (res, value) {
  let diff = dayjs(value.EndTime).diff(dayjs(value.StartTime), "hour",true) % 60;
  let count;

  if(value.RecurrenceRule != null) {
    count =  parseInt(value.RecurrenceRule.split("COUNT=")[1]);
    if(value.RecurrenceException){
    if(value.RecurrenceException.match(/,/g) ) {
      if(value.RecurrenceException.match(/,/g).length == 0) {
        console.log(value.RecurrenceException.match(/,/g).length);
        count = count -1;
      }
    } else if(value.RecurrenceException && value.RecurrenceException.match(/,/g).length == 1) {
      console.log(value.RecurrenceException.match(/,/g).length);      
      count = count -2;
    } else if(value.RecurrenceException && value.RecurrenceException.match(/,/g).length == 2) {
      console.log(value.RecurrenceException.match(/,/g).length);
      count = count -3;
    } else
    if(value.RecurrenceException && value.RecurrenceException.match(/,/g).length == 3) {
       count = count -4;
    };
  }
  }
  else if(value.RecurrenceRule == null) {
       count = 1;
  }
  if (!res[value.Client]) {
    res[value.Client] = {

      week: value.week,
      km: value.km * count,
      Client: value.Client,
      count: count,
      difference: diff * count
    };
    result.push(res[value.Client]);


  } else {
    res[value.Client].km += value.km * count;
    res[value.Client].difference += diff * count;
  }

  return res;
}, {});

How do I go about this situation? the output now is that instead of creating two rows (week 23 & 24), it sums all the appointments of Steven in week 23 which is incorrect because 0.5 hour took place in another week.

{Client: "Steven"
count: 5
difference: 40.5
km: 528
week: 23}

So the ideal output is:

{
Client: "Steven"
count: 5
difference: 40
km: 440
week: 23 
},

{
Client: "Steven"
count: 1
difference: 0.5
km: 88
week: 24
}

You can have rows with the same week number as long as the Client differs.

I hope i made it clear and if you need more context, please mention

Upvotes: 2

Views: 318

Answers (2)

Alex L
Alex L

Reputation: 4241

Building on @ajai's answer (and using his input first for comparison), hopefully giving you what you need (and using reduce).

const data = [  
  { 
   CreatedBy: "bob",
   Description: "smthng",
   EndTime: "2020-06-01T17:00:00.000Z",
   EndTimezone: null,
   Id: 3,
   IsAllDay: false,
   Client: "Steven",
   Location: "smthng",
   RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
   StartTime: "2020-06-01T09:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng",
   km: 88,
   week: 23,
   _id: "5ecc6f4a08c79c6328974699"
  }, 
  { 
   CreatedBy: "bob",
   Description: "smthng",
   EndTime: "2020-06-08T10:30:00.000Z",
   EndTimezone: null,
   Id: 4,
   IsAllDay: false,
   Client: "Steven",
   Location: "smthng",
   RecurrenceRule: null,
   StartTime: "2020-06-08T10:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng"  ,
   km: 88,
   week: 24,
   _id: "5ed450d299d5303bd0338a7f"
  },
  { 
   CreatedBy: "bob",
   Description: "smthng",
   EndTime: "2020-06-01T17:00:00.000Z",
   EndTimezone: null,
   Id: 3,
   IsAllDay: false,
   Client: "Steven",
   Location: "smthng",
   RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
   StartTime: "2020-06-01T09:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng",
   km: 40,
   week: 23,
   _id: "5ecc6f4a08c79c6328974699"
  },
  { 
   CreatedBy: "bob",
   Description: "smtng",
   EndTime: "2020-06-01T17:00:00.000Z",
   EndTimezone: null,
   Id: 3,
   IsAllDay: false,
   Client: "ajai",
   Location: "smthng",
   RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
   StartTime: "2020-06-01T09:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng",
   km: 88,
   week: 23,
   _id: "5ecc6f4a08c79c6328974699"
  }
]    
  

const result = Object.values(data.reduce((aggObj, item) => {
  const stringID = `${item.Client}_${item.week}`;
  const diff = (new Date(item.EndTime) - new Date(item.StartTime))/(1000*60*60);
  const RecurrenceObj = item.RecurrenceRule ?
    item.RecurrenceRule.split(";").map(a => {
      //console.log(a)
      return a.split("=") || ["_", null];          
    }).reduce((aggObj, [key,val]) => {
      aggObj[key] = val;
      return aggObj;
    })
    : {COUNT: 1};
    
  if (aggObj[stringID]){
    aggObj[stringID].km += (item.km * RecurrenceObj.COUNT);
    aggObj[stringID].count += parseInt(RecurrenceObj.COUNT);
    aggObj[stringID].difference += (diff * RecurrenceObj.COUNT);
  }
  else {  
    aggObj[stringID] = {
      Client: item.Client,
      km: item.km * RecurrenceObj.COUNT,
      count: parseInt(RecurrenceObj.COUNT),
      difference: diff * RecurrenceObj.COUNT,
      week: item.week
    };
  }
  return aggObj;
}, {}));

/*
for(var i=0;i<=data.length-1;i++){
   let pos = result.findIndex(el=> `${el.Client}-${el.week}`==`${data[i].Client}-${data[i].week}`)
   if(pos==-1){
     result.push({Client: data[i]['Client'],count: 1,difference: 0,km: data[i]['km'],week: data[i]['week']})
   }else{
     result[pos]['count'] = result[pos]['count'] + 1;
     result[pos]['km'] = result[pos]['km'] + data[i]['km'];
   }
}
*/
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

OUTPUT:

[
  {
    "Client": "Steven",
    "km": 640,
    "count": 10,
    "difference": 80,
    "week": 23
  },
  {
    "Client": "Steven",
    "km": 88,
    "count": 1,
    "difference": 0.5,
    "week": 24
  },
  {
    "Client": "ajai",
    "km": 440,
    "count": 5,
    "difference": 40,
    "week": 23
  }
]

Now with your exact input:

const data = [  
  { 
   CreatedBy: "bob",
   Description: "smthng",
   EndTime: "2020-06-01T17:00:00.000Z",
   EndTimezone: null,
   Id: 3,
   IsAllDay: false,
   Client: "Steven",
   Location: "smthng",
   RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
   StartTime: "2020-06-01T09:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng",
   km: 88,
   week: 23,
   _id: "5ecc6f4a08c79c6328974699"
  }, 
  { 
   CreatedBy: "bob",
   Description: "smthng",
   EndTime: "2020-06-08T10:30:00.000Z",
   EndTimezone: null,
   Id: 4,
   IsAllDay: false,
   Client: "Steven",
   Location: "smthng",
   RecurrenceRule: null,
   StartTime: "2020-06-08T10:00:00.000Z",
   StartTimezone: null,
   Subject: "smthng"  ,
   km: 88,
   week: 24,
   _id: "5ed450d299d5303bd0338a7f"
  }
]    
  

const result = Object.values(data.reduce((aggObj, item) => {
  const stringID = `${item.Client}_${item.week}`;
  const diff = (new Date(item.EndTime) - new Date(item.StartTime))/(1000*60*60);
  const RecurrenceObj = item.RecurrenceRule ?
    item.RecurrenceRule.split(";").map(a => {
      //console.log(a)
      return a.split("=") || ["_", null];
    }).reduce((aggObj, [key,val]) => {
      aggObj[key] = val;
      return aggObj;
    })
    : {COUNT: 1};
    
  if (aggObj[stringID]){
    aggObj[stringID].km += (item.km * RecurrenceObj.COUNT);
    aggObj[stringID].count += parseInt(RecurrenceObj.COUNT);
    aggObj[stringID].difference += (diff * RecurrenceObj.COUNT);
  }
  else {  
    aggObj[stringID] = {
      Client: item.Client,
      km: item.km * RecurrenceObj.COUNT,
      count: parseInt(RecurrenceObj.COUNT),
      difference: diff * RecurrenceObj.COUNT,
      week: item.week
    };
  }
  return aggObj;
}, {}));

/*
for(var i=0;i<=data.length-1;i++){
   let pos = result.findIndex(el=> `${el.Client}-${el.week}`==`${data[i].Client}-${data[i].week}`)
   if(pos==-1){
     result.push({Client: data[i]['Client'],count: 1,difference: 0,km: data[i]['km'],week: data[i]['week']})
   }else{
     result[pos]['count'] = result[pos]['count'] + 1;
     result[pos]['km'] = result[pos]['km'] + data[i]['km'];
   }
}
*/
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

OUTPUT:

[
  {
    "Client": "Steven",
    "km": 440,
    "count": 5,
    "difference": 40,
    "week": 23
  },
  {
    "Client": "Steven",
    "km": 88,
    "count": 1,
    "difference": 0.5,
    "week": 24
  }
]

Upvotes: 1

Ajai
Ajai

Reputation: 391

I'm not sure this is what your expectation and I'm not sure what to do with difference just explain me if this is not satisfied.

var data = [  
{ 
 CreatedBy: "bob",
 Description: "smthng",
 EndTime: "2020-06-01T17:00:00.000Z",
 EndTimezone: null,
 Id: 3,
 IsAllDay: false,
 Client: "Steven",
 Location: "smthng",
 RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
 StartTime: "2020-06-01T09:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng",
 km: 88,
 week: 23,
 _id: "5ecc6f4a08c79c6328974699"
}, 
{ 
 CreatedBy: "bob",
 Description: "smthng",
 EndTime: "2020-06-08T10:30:00.000Z",
 EndTimezone: null,
 Id: 4,
 IsAllDay: false,
 Client: "Steven",
 Location: "smthng",
 RecurrenceRule: null,
 StartTime: "2020-06-08T10:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng"  ,
 km: 88,
 week: 24,
 _id: "5ed450d299d5303bd0338a7f"
},
{ 
 CreatedBy: "bob",
 Description: "smthng",
 EndTime: "2020-06-01T17:00:00.000Z",
 EndTimezone: null,
 Id: 3,
 IsAllDay: false,
 Client: "Steven",
 Location: "smthng",
 RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
 StartTime: "2020-06-01T09:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng",
 km: 40,
 week: 23,
 _id: "5ecc6f4a08c79c6328974699"
},
{ 
 CreatedBy: "bob",
 Description: "smtng",
 EndTime: "2020-06-01T17:00:00.000Z",
 EndTimezone: null,
 Id: 3,
 IsAllDay: false,
 Client: "ajai",
 Location: "smthng",
 RecurrenceRule: "FREQ=DAILY;INTERVAL=1;COUNT=5;",
 StartTime: "2020-06-01T09:00:00.000Z",
 StartTimezone: null,
 Subject: "smthng",
 km: 88,
 week: 23,
 _id: "5ecc6f4a08c79c6328974699"
}
  ]    
let result = []
for(var i=0;i<=data.length-1;i++){
   let pos = result.findIndex(el=> `${el.Client}-${el.week}`==`${data[i].Client}-${data[i].week}`)
   if(pos==-1){
     result.push({Client: data[i]['Client'],count: 1,difference: 0,km: data[i]['km'],week: data[i]['week']})
   }else{
     result[pos]['count'] = result[pos]['count'] + 1;
     result[pos]['km'] = result[pos]['km'] + data[i]['km'];
   }
}
console.log(result)

 

Upvotes: 1

Related Questions