3

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.

Andriy Yushko
  • 395
  • 5
  • 21
  • It seems a similar problem to merging intervals (https://leetcode.com/problems/merge-intervals/). You may check it out, there's a solution tab there. – vitkarpov May 14 '20 at 08:42

2 Answers2

3

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I understand that but how to group these items in array by time interval – Andriy Yushko May 14 '20 at 08:55
  • do you need to take *dayjs*? if so, you could check if two times have a smaller duration than your wanted interval. if not, or if not take a difference, you could get from all the total seconds ad check if the delta is in the wanted range. – Nina Scholz May 14 '20 at 09:03
  • yes I use dayjs for check enterence item in time period – Andriy Yushko May 14 '20 at 09:09
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

Andriy Yushko
  • 395
  • 5
  • 21