2

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

2 Answers 2

1

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
  }
]
Sign up to request clarification or add additional context in comments.

4 Comments

thank you for your answer. However I get this error msg: `TS2339: Property 'fromEntries' does not exist on type 'ObjectConstructor'. Should I update my IDE settings to es2019 with the risk of the app not working on all browsers,are there any other alternatives which do not require a higher typescript version?
IE is the only major browser you wouldn't be supporting - caniuse.com/#search=fromEntries - I can post a work-around / polyfill for that. I edited my answer to use reduce, instead, is that ok?
I swapped Object.fromEntries for Reduce, which is supported since IE 9 - caniuse.com/#search=array%20reduce - is that enough browser support for you?
If you are using typeScript, you should also be able to use the "latest-and-greatest" without worries, as you can transpile typeScript down to es2015/ES6 or down to ES3 if you want to. But yes, perhaps your typeScript version is one which did not have Object.fromEntries included in its compiler/transpiler
1

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)

 

1 Comment

thank you for your reply. The 'difference' variable is the difference in time between the 'StartTime' and 'EndTime' properties. So I want to sum these differences for the particular client in that week. I hope i cleared it up for you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.