user0101
user0101

Reputation: 1517

Split array of objects into 2hrs span groups

I need to split an array of objects in a shape of

{
  eventStart: 1575621000000,
  data: 'Some data' // not relevant
}

by chunks of 2 hours span, starting with every hour on the hour (beginning of hour), like: 10.00 - 12.00, 12.00 - 14.00, etc

this is what I came up with but don't think it's anywhere near performant solution:

Please note the day which is just a moment().startOf('day') const

data => data.reduce((acc, { eventStart, ...rest }) => {
    if (moment(eventStart).isBetween(moment(day).add(8, 'hours'), moment(day).add(10, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '8-10': [...acc['8-10'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(10, 'hours'), moment(day).add(12, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '10-12': [...acc['10-12'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(12, 'hours'), moment(day).add(14, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '12-14': [...acc['12-14'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(14, 'hours'), moment(day).add(16, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '14-16': [...acc['14-16'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(16, 'hours'), moment(day).add(18, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '16-18': [...acc['16-18'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(18, 'hours'), moment(day).add(20, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '18-20': [...acc['18-20'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(20, 'hours'), moment(day).add(22, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '20-22': [...acc['20-22'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(22, 'hours'), moment(day).add(24, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '22-24': [...acc['22-24'], rest] }
      )
    }

    return acc
  }, {
    '8-10': [],
    '10-12': [],
    '12-14': [],
    '14-16': [],
    '16-18': [],
    '18-20': [],
    '20-22': [],
    '22-24': []
  })

I am cool with Lodash approach if anyone comes up with one.

Example data:

[{"data":42986084,"eventStart":1575621000000},{"data":43729858,"eventStart":1575626400000},{"data":43738365,"eventStart":1575626400000},{"data":43738483,"eventStart":1575626400000},{"data":43688900,"eventStart":1575626400000},{"data":43701367,"eventStart":1575628200000},{"data":43701506,"eventStart":1575628200000},{"data":43675303,"eventStart":1575621000000},{"data":43690259,"eventStart":1575621000000},{"data":43695785,"eventStart":1575628200000},{"data":43695820,"eventStart":1575628200000},{"data":43695827,"eventStart":1575628200000},{"data":43699341,"eventStart":1575628200000},{"data":43699369,"eventStart":1575628200000},{"data":43699424,"eventStart":1575628200000},{"data":43699428,"eventStart":1575628200000},{"data":43700003,"eventStart":1575628200000},{"data":43701004,"eventStart":1575628200000},{"data":43698552,"eventStart":1575628200000},{"data":43741641,"eventStart":1575619200000},{"data":43741909,"eventStart":1575619200000},{"data":43739045,"eventStart":1575624600000},{"data":43742137,"eventStart":1575624600000},{"data":43742680,"eventStart":1575619200000},{"data":43744043,"eventStart":1575619200000},{"data":43784844,"eventStart":1575619200000},{"data":43785707,"eventStart":1575624600000},{"data":43764294,"eventStart":1575621900000},{"data":43787721,"eventStart":1575622800000},{"data":43787722,"eventStart":1575622800000},{"data":43787723,"eventStart":1575622800000},{"data":43787737,"eventStart":1575622800000},{"data":43767839,"eventStart":1575621600000},{"data":43726394,"eventStart":1575626400000},{"data":43810835,"eventStart":1575628200000},{"data":43725116,"eventStart":1575618600000},{"data":43793011,"eventStart":1575622800000},{"data":43793046,"eventStart":1575626400000},{"data":43793062,"eventStart":1575628200000},{"data":43737559,"eventStart":1575619200000},{"data":43737939,"eventStart":1575619200000},{"data":43737938,"eventStart":1575624600000},{"data":43792981,"eventStart":1575624600000},{"data":43735362,"eventStart":1575621600000},{"data":43784352,"eventStart":1575619200000},{"data":43784392,"eventStart":1575619200000},{"data":43731320,"eventStart":1575624600000},{"data":43732363,"eventStart":1575624600000},{"data":43785780,"eventStart":1575622800000},{"data":43785782,"eventStart":1575622800000},{"data":43785790,"eventStart":1575628200000},{"data":43785792,"eventStart":1575628200000},{"data":43780474,"eventStart":1575621000000},{"data":43780213,"eventStart":1575624000000},{"data":43811157,"eventStart":1575626400000},{"data":43811324,"eventStart":1575626400000},{"data":43811121,"eventStart":1575628200000},{"data":41965260,"eventStart":1575624600000},{"data":43793228,"eventStart":1575622800000},{"data":43735069,"eventStart":1575626400000},{"data":43550395,"eventStart":1575621000000},{"data":43550795,"eventStart":1575628200000},{"data":43674957,"eventStart":1575619200000},{"data":43675056,"eventStart":1575619500000},{"data":43699933,"eventStart":1575626400000},{"data":43700079,"eventStart":1575626400000},{"data":43735147,"eventStart":1575626400000},{"data":43735110,"eventStart":1575626400000},{"data":43732832,"eventStart":1575626400000},{"data":43732877,"eventStart":1575626400000},{"data":43733772,"eventStart":1575626400000},{"data":43761754,"eventStart":1575626400000},{"data":43694264,"eventStart":1575622800000},{"data":43748186,"eventStart":1575626400000},{"data":43720156,"eventStart":1575622800000},{"data":43720671,"eventStart":1575622800000},{"data":43589280,"eventStart":1575626400000},{"data":43593385,"eventStart":1575626400000},{"data":43757509,"eventStart":1575619200000},{"data":43757556,"eventStart":1575621000000},{"data":43535382,"eventStart":1575619200000},{"data":43371974,"eventStart":1575626400000},{"data":43752370,"eventStart":1575621000000},{"data":43752371,"eventStart":1575621000000},{"data":43784503,"eventStart":1575619080000},{"data":43784761,"eventStart":1575620400000},{"data":43784650,"eventStart":1575621720000},{"data":43784748,"eventStart":1575623040000},{"data":43784836,"eventStart":1575624360000},{"data":43785638,"eventStart":1575625680000},{"data":43727654,"eventStart":1575619800000},{"data":43727744,"eventStart":1575622200000},{"data":43727655,"eventStart":1575624600000},{"data":43727728,"eventStart":1575627000000}]

Expected output would be any iterable form really. An example might be the initialValue in reduce function:

{
    '8-10': [], // nothing found for this criteria
    '10-12': [
               {
                 eventStart: 1575626400000,
                 data: 444
               },
               {
                 eventStart: 1575626400000,
                 data: 555
               }
             ],  // 2 objects fit the 10-12 range
    '12-14': [], // nothing found for this criteria
    '14-16': [], // nothing found for this criteria
    '16-18': [], // nothing found for this criteria
    '18-20': [], // nothing found for this criteria
    '20-22': [], // nothing found for this criteria
    '22-24': [] // nothing found for this criteria
  }

Adding a code snippet for the question for others to run and work on

day = moment().startOf('day')
data = [{"data":42986084,"eventStart":1575621000000},{"data":43729858,"eventStart":1575626400000},{"data":43738365,"eventStart":1575626400000},{"data":43738483,"eventStart":1575626400000},{"data":43688900,"eventStart":1575626400000},{"data":43701367,"eventStart":1575628200000},{"data":43701506,"eventStart":1575628200000},{"data":43675303,"eventStart":1575621000000},{"data":43690259,"eventStart":1575621000000},{"data":43695785,"eventStart":1575628200000},{"data":43695820,"eventStart":1575628200000},{"data":43695827,"eventStart":1575628200000},{"data":43699341,"eventStart":1575628200000},{"data":43699369,"eventStart":1575628200000},{"data":43699424,"eventStart":1575628200000},{"data":43699428,"eventStart":1575628200000},{"data":43700003,"eventStart":1575628200000},{"data":43701004,"eventStart":1575628200000},{"data":43698552,"eventStart":1575628200000},{"data":43741641,"eventStart":1575619200000},{"data":43741909,"eventStart":1575619200000},{"data":43739045,"eventStart":1575624600000},{"data":43742137,"eventStart":1575624600000},{"data":43742680,"eventStart":1575619200000},{"data":43744043,"eventStart":1575619200000},{"data":43784844,"eventStart":1575619200000},{"data":43785707,"eventStart":1575624600000},{"data":43764294,"eventStart":1575621900000},{"data":43787721,"eventStart":1575622800000},{"data":43787722,"eventStart":1575622800000},{"data":43787723,"eventStart":1575622800000},{"data":43787737,"eventStart":1575622800000},{"data":43767839,"eventStart":1575621600000},{"data":43726394,"eventStart":1575626400000},{"data":43810835,"eventStart":1575628200000},{"data":43725116,"eventStart":1575618600000},{"data":43793011,"eventStart":1575622800000},{"data":43793046,"eventStart":1575626400000},{"data":43793062,"eventStart":1575628200000},{"data":43737559,"eventStart":1575619200000},{"data":43737939,"eventStart":1575619200000},{"data":43737938,"eventStart":1575624600000},{"data":43792981,"eventStart":1575624600000},{"data":43735362,"eventStart":1575621600000},{"data":43784352,"eventStart":1575619200000},{"data":43784392,"eventStart":1575619200000},{"data":43731320,"eventStart":1575624600000},{"data":43732363,"eventStart":1575624600000},{"data":43785780,"eventStart":1575622800000},{"data":43785782,"eventStart":1575622800000},{"data":43785790,"eventStart":1575628200000},{"data":43785792,"eventStart":1575628200000},{"data":43780474,"eventStart":1575621000000},{"data":43780213,"eventStart":1575624000000},{"data":43811157,"eventStart":1575626400000},{"data":43811324,"eventStart":1575626400000},{"data":43811121,"eventStart":1575628200000},{"data":41965260,"eventStart":1575624600000},{"data":43793228,"eventStart":1575622800000},{"data":43735069,"eventStart":1575626400000},{"data":43550395,"eventStart":1575621000000},{"data":43550795,"eventStart":1575628200000},{"data":43674957,"eventStart":1575619200000},{"data":43675056,"eventStart":1575619500000},{"data":43699933,"eventStart":1575626400000},{"data":43700079,"eventStart":1575626400000},{"data":43735147,"eventStart":1575626400000},{"data":43735110,"eventStart":1575626400000},{"data":43732832,"eventStart":1575626400000},{"data":43732877,"eventStart":1575626400000},{"data":43733772,"eventStart":1575626400000},{"data":43761754,"eventStart":1575626400000},{"data":43694264,"eventStart":1575622800000},{"data":43748186,"eventStart":1575626400000},{"data":43720156,"eventStart":1575622800000},{"data":43720671,"eventStart":1575622800000},{"data":43589280,"eventStart":1575626400000},{"data":43593385,"eventStart":1575626400000},{"data":43757509,"eventStart":1575619200000},{"data":43757556,"eventStart":1575621000000},{"data":43535382,"eventStart":1575619200000},{"data":43371974,"eventStart":1575626400000},{"data":43752370,"eventStart":1575621000000},{"data":43752371,"eventStart":1575621000000},{"data":43784503,"eventStart":1575619080000},{"data":43784761,"eventStart":1575620400000},{"data":43784650,"eventStart":1575621720000},{"data":43784748,"eventStart":1575623040000},{"data":43784836,"eventStart":1575624360000},{"data":43785638,"eventStart":1575625680000},{"data":43727654,"eventStart":1575619800000},{"data":43727744,"eventStart":1575622200000},{"data":43727655,"eventStart":1575624600000},{"data":43727728,"eventStart":1575627000000}]

res = data.reduce((acc, { eventStart, ...rest }) => {
    if (moment(eventStart).isBetween(moment(day).add(8, 'hours'), moment(day).add(10, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '8-10': [...acc['8-10'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(10, 'hours'), moment(day).add(12, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '10-12': [...acc['10-12'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(12, 'hours'), moment(day).add(14, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '12-14': [...acc['12-14'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(14, 'hours'), moment(day).add(16, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '14-16': [...acc['14-16'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(16, 'hours'), moment(day).add(18, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '16-18': [...acc['16-18'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(18, 'hours'), moment(day).add(20, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '18-20': [...acc['18-20'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(20, 'hours'), moment(day).add(22, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '20-22': [...acc['20-22'], rest] }
      )
    }
    if (moment(eventStart).isBetween(moment(day).add(22, 'hours'), moment(day).add(24, 'hours'))) {
      acc = Object.assign(
        {},
        acc,
        { '22-24': [...acc['22-24'], rest] }
      )
    }

    return acc
  }, {
    '8-10': [],
    '10-12': [],
    '12-14': [],
    '14-16': [],
    '16-18': [],
    '18-20': [],
    '20-22': [],
    '22-24': []
  })
  console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

Upvotes: 2

Views: 235

Answers (1)

Ori Drori
Ori Drori

Reputation: 191976

You can use lodash's _.groupBy() and generate the key by creating a date from eventStart, rounding down to the closest even hour (start), and returning a range of start - start + 2:

const data = [{"data":42986084,"eventStart":1575621000000},
{"data":43729858,"eventStart":1575626400000},{"data":43727728,"eventStart":1575627000000}];

const result = _.groupBy(data, o => {
  const hour = new Date(o.eventStart).getHours(); // get the hour
  const start = hour - hour % 2; // normalize to the closest even hour
  
  return `${start}-${start + 2}`; // get the key
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

And the same idea using Array.reduce():

const data = [{"data":42986084,"eventStart":1575621000000},
{"data":43729858,"eventStart":1575626400000},{"data":43727728,"eventStart":1575627000000}];

const createRangeKey = eventStart => {
  const hour = new Date(eventStart).getHours(); // get the hour 
  const start = hour - hour % 2; // normalize to the closest even hour
  
  return `${start}-${start + 2}`; // get the key
};

const result = data.reduce((r, o) => {
  const key = createRangeKey(o.eventStart); // get the key
  
  if(!r[key]) r[key] = []; // init if not existing on the object
  
  r[key].push(o); // add the object to the key
  
  return r;
}, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

If you need to filter out hours that are not in the 8-24 range, you can check if the start is less than 8. In this example {"data":"ignore","eventStart": 1575669600000} would be ignored.

const data = [{"data":42986084,"eventStart":1575621000000},
{"data":43729858,"eventStart":1575626400000},{"data":43727728,"eventStart":1575627000000}, {"data":"ignore","eventStart": 1575669600000}];

const result = data.reduce((r, o) => {
  const hour = new Date(o.eventStart).getHours(); // get the hour
  
  const start = hour - hour % 2; // normalize to the closest even hour
  
  if(start < 8) return r;
  
  const key = `${start}-${start + 2}`; // get the key
  
  if(!r[key]) r[key] = []; // init if not existing on the object
  
  r[key].push(o); // add the object to the key
  
  return r;
}, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 3

Related Questions