How to group item of array by time with step

Viewed 146

I have an array like this:

let arr = [
  {
    title: 'Some title',
    start: '09:30:59',
    end: '09:33:59',
  },
  {
    title: 'Some title',
    start: '09:33:59',
    end: '09:35:59',
  },
  {
    title: 'Some title',
    start: '09:35:59',
    end: '09:40:59',
  },
  {
    title: 'Some title',
    start: '09:30:59',
    end: '09:45:59',
  }
  ...
];

And I want to get array grouped by some step for example 10:

let result = [
  {
    start: '09:30:59',
    end: '09:40:59',
    arr: [
      {
        title: 'Some title',
        start: '09:30:59',
        end: '09:33:59',
      },
      {
        title: 'Some title',
        start: '09:33:59',
        end: '09:35:59',
      },
    ],
  }, 
  {
    start: '09:40:59',
    end: '09:50:59',
    arr: [
      {
        title: 'Some title',
        start: '09:35:59',
        end: '09:40:59',
      },
      {
        title: 'Some title',
        start: '09:30:59',
        end: '09:45:59',
      }
    ],
  },        
    ...
];

I tried do it:

let step = 10;
let diffMinutes = dayjs(arr[arr.length - 1].end).diff(arr[0].start, 'm') / step;
let newArr  = [];
let result = [];
for (let t = 0; t < diffMinutes; t++) {
  newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (dayjs(arr[i].start).isBetween(arr[0].start, dayjs(arr[0].start).add(step, 'm').format('YYYY-MM-DD HH:mm'))) {
      newArr.push(state.events[i]);
    }
  }
  result.push(
    {
      ...
      arr: newArr
    }
  )
}       

I added condition with dayjs that check if event start time enters a certain period of time. I think it can be made easier than I did. Result shout be array grouped by time with stem 10. Sopouse that in else statment I should use last item of last array result. But it work only for first iteration, how to do that in next I dot know.

Help me please.

2 Answers

You could take the first four characters of the time and group by this value.

let array = [{ title: 'Some title', start: '09:30:59', end: '09:33:59' }, { title: 'Some title', start: '09:33:59', end: '09:35:59' }, { title: 'Some title', start: '09:35:59', end: '09:40:59' }, { title: 'Some title', start: '09:30:59', end: '09:45:59' }],
    group = s => s.slice(0, 4),
    result = Object.values(array.reduce((r, o) => {
        const key = group(o.start);
        r[key] = r[key] || { start: key + '0:00', array: [] };
        r[key].array.push(o);
        return r;
    }, {}));

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

Another solution could be to use time values as seconds with an interval of seconds. The result is grouped by the interval and start and end properties are calculated with the given interval.

let array = [{ title: 'Some title', start: '09:30:59', end: '09:33:59' }, { title: 'Some title', start: '09:33:59', end: '09:35:59' }, { title: 'Some title', start: '09:35:59', end: '09:40:59' }, { title: 'Some title', start: '09:30:59', end: '09:45:59' }],
    seconds = time => time.split(':').reduce((a, b) => a * 60 + +b),
    //interval = 600,               // in seconds, here 10 minutes
    interval = seconds('00:10:00'), // or by taking the seconds from a time string
    group = time => Math.floor(seconds(time) / interval),
    getTime = seconds => [3600, 60, 1]
        .map(factor => {
            var v = Math.floor(seconds / factor);
            seconds %= factor;
            return v.toString().padStart(2, 0);
        })
        .join(':'),
    result = Object.values(array.reduce((r, o) => {
        const key = group(o.start);
        r[key] = r[key] || { start: getTime(key * interval), end: getTime((key + 1) * interval - 1), array: [] };
        r[key].array.push(o);
        return r;
    }, {}));

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

Resolved problem example

let step = 5;
let diffMinutes = Math.round(
  dayjs(arr[arr.length - 1].end).diff(arr[0].start, "m") / step
);
let result = [];
let newArr = [];

for (var i = 0; i <= diffMinutes; i++) {
  newArr = [];
  if (i === 0) {
    for (let j = 0; j < arr.length; j++) {
      if (
        moment(arr[j].start).isSame(arr[0].start) ||
        moment(arr[j].start).isSame(
          dayjs(arr[0].start).add(step, "m").format("YYYY-MM-DD HH:mm:ss")
        ) ||
        moment(arr[j].start).isBetween(
          arr[0].start,
          dayjs(arr[0].start).add(step, "m").format("YYYY-MM-DD HH:mm:ss")
        )
      ) {
        newArr.push(arr[j]);
      }
    }
  } else {
    let lastResult = result[result.length - 1];
    let lastEllArr = lastResult[lastResult.length - 1];

    console.log("i" + i, lastEllArr.start);
    for (let j = 0; j < arr.length; j++) {
      if (
        moment(arr[j].start).isSame(
          dayjs(lastEllArr.end).add(step, "m").format("YYYY-MM-DD HH:mm:ss")
        ) ||
        moment(arr[j].start).isBetween(
          lastEllArr.end,
          dayjs(lastEllArr.end).add(step, "m").format("YYYY-MM-DD HH:mm:ss")
        )
      ) {
        newArr.push(arr[j]);
      }
    }
  }
  if (newArr.length !== 0) {
    result.push(newArr);
  }
}

If anyone suggests improving the code I would appreciate it

Related