Home > database >  Convert a list of objects with a range of minutes to an hourly list
Convert a list of objects with a range of minutes to an hourly list

Time:09-15

I have a list with minute blocks objects, it contains the start and end hour/minute, according to this I must build a new list of blocks by hour and minutes occupied. Always in the same range below one hour, for this example only 30 minutes, and they cannot overlap.

Example of minute block (30-minute block starting at 00:00 and ending at 0:30).

let blockMinute = {
  hourInit: 0,
  minuteInit: 0,
  hourEnd: 0,
  minuteEnd: 30
}

Example hour block (expected).

[
{
  hourInit: 0,
  hourEnd: 1,
  accuMinutes: 30
}
]

A new time block must be created, because it starts at 0:00 and ends at 0:30, then the occupied hour is from 0 to 1, and occupies 30 minutes in that hour.

Another example is for a 30-minute block starting at 0:45 and ending at 1:15.

let blockMinute2 = {
    hourInit: 0,
    minuteInit: 45,
    hourEnd: 1,
    minuteEnd: 15
}
// Expected result
[
{
    hourInit: 0,
    hourEnd: 1,
    accuMinutes: 15 //unresolved
},
{
    hourInit: 1,
    hourEnd: 2,
    accuMinutes: 15 //unresolved
}
]

Two hour blocks must be created, because it starts at 0:45 and ends at 1:15, so it creates two hours from 0 to 1 and 1 to 2, and of these hours it occupies 15 minutes in each one. The block was 30 minutes, but it was divided between the two hours.

This is my solution:

I have tried to create a solution but it gives me a lot of problems when a block of minutes crosses an hour it should generate blocks of hours and the minutes it occupies, I can't determine them. And also when they are at the limit of an hour, for example from 0:30 to 1:00, it counts as two hours, when it should be one from 0 to 1.

let blockMinute = {
    hourInit: 0,
    minuteInit: 0,
    hourEnd: 0,
    minuteEnd: 30
}

let blockMinute2 = {
    hourInit: 0,
    minuteInit: 45,
    hourEnd: 1,
    minuteEnd: 15
}
// Always the same range, for example all 30 minutes
let blocksMinute = [blockMinute, blockMinute2];

let blockHourExpected = [];
blocksMinute.forEach((blockMinute) => {
  let hourInit = blockMinute.hourInit;
  let minuteInit = blockMinute.minuteInit;
  let hourEnd = blockMinute.hourEnd;
  let minuteEnd = blockMinute.minuteEnd;
  for (let i = hourInit; i <= hourEnd; i  ) {
    let exist = blockHourExpected.find((blockHour) => blockHour.hourInit == i);
    if (!exist) {
      blockHourExpected.push({
        hourInit: i,
        hourEnd: i   1,
        accuMinutes: 0 //unresolved
      })
    }
  }
});
console.log(blockHourExpected)

Expected result

let blockHourExpectedExample = [{
    hourInit: 0,
    hourEnd: 1,
    accuMinutes: 45
 },
  {
    hourInit: 1,
    hourEnd: 2,
    accuMinutes: 15
 }
]

CodePudding user response:

That is a quite hard one...
The challenge is about the "meeting" starting in the previous hour ending in the second.

You have to use an object to accumulate all spent minutes...
Then extract the "hour" objects to return your expected result.

See comments in code. ;)

let blockMinute = {
  hourInit: 0,
  minuteInit: 0,
  hourEnd: 0,
  minuteEnd: 30
};
let blockMinute2 = {
  hourInit: 0,
  minuteInit: 45,
  hourEnd: 1,
  minuteEnd: 15
};
let blocksMinute = [blockMinute, blockMinute2];

// Function to set an "hour" object, if not existing.
function setHourObject(hourInit) {
  return {
    hourInit: hourInit,
    hourEnd: hourInit   1,
    accMinutes: 0
  };
}

function getAccumulatedMinutesPerHour(blocks) {
  // Use an object to accumulate spent minutes
  const hours = {};

  // Loop all blocks
  blocks.forEach((block) => {
  
    // If start and end hour is the same
    if (block.hourInit === block.hourEnd) {
    
      // Create the start hour if does not already exist in the "hours" object
      if (!hours[block.hourInit.toString()]) {
        hours[block.hourInit.toString()] = setHourObject(block.hourInit);
      }
      hours[block.hourInit.toString()].accMinutes  =
        block.minuteEnd - block.minuteInit;
        
    // if start and end hour are different
    } else {
    
      // Create the start hour if does not already exist in the "hours" object
      if (!hours[block.hourInit.toString()]) {
        hours[block.hourInit.toString()] = setHourObject(block.hourInit);
      }
      // Add spent minutes
      hours[block.hourInit.toString()].accMinutes  = 60 - block.minuteInit;

      // Create the end hour if does not already exist in the "hours" object
      if (!hours[block.hourEnd.toString()]) {
        hours[block.hourEnd.toString()] = setHourObject(block.hourEnd);
      }
      // Add spent minutes
      hours[block.hourEnd.toString()].accMinutes  = block.minuteEnd;
    }
  });
  
  // return the object (nested in the "hours" object) as an array
  return Object.keys(hours).map((hour) => hours[hour]);
}

const r = getAccumulatedMinutesPerHour(blocksMinute);
console.log(r);

CodePudding user response:

Seems you're already almost there. It's kinda simple algorithm puzzle. I've added a few lines to your codes and seems like it gives the result what you want to get.

let blockMinute1 = {
  hourInit: 0,
  minuteInit: 0,
  hourEnd: 0,
  minuteEnd: 30
}

let blockMinute2 = {
  hourInit: 0,
  minuteInit: 45,
  hourEnd: 1,
  minuteEnd: 15
}

// Always the same range, for example all 30 minutes
let blocksMinutes = [blockMinute1, blockMinute2];
let blockHourExpected = [];

blocksMinutes.forEach((blockMinute) => {
  let hourInit = blockMinute.hourInit;
  let minuteInit = blockMinute.minuteInit;
  let hourEnd = blockMinute.hourEnd;
  let minuteEnd = blockMinute.minuteEnd;

  for (let i = hourInit; i <= hourEnd; i  ) {
    let accuMinutes = hourEnd === hourInit ? minuteEnd - minuteInit : 60 - minuteInit;

    let exist = blockHourExpected.find((blockHour) => blockHour.hourInit == i);
    if (exist) {
      exist.accuMinutes  = accuMinutes;
    } else {
      blockHourExpected.push({
        hourInit: i,
        hourEnd: i   1,
        accuMinutes: accuMinutes
      })
    }
  }
});

console.log(blockHourExpected);

  • Related