Reputation: 135
I have an array of time ranges (in string format) like this:
["09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00", "11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00", "16:00 - 16:30", "17:00 - 17:30"]
How to get a new array (or manipulating the starting one) that contains:
The result of the above example must be:
["09:00 - 11:00", "11:30 - 13:00", "16:00 - 16:30", "17:00 - 17:30"]
My attempt:
let start = ["09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00", "11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00", "16:00 - 16:30", "17:00 - 17:30"]
let compressed = [];
for (let i = 0; i < start.length; i++) {
let currentSlot = start[i];
let nextSlot = start[i + 1];
if (currentSlot && nextSlot) {
let currentSlotStartHour = currentSlot.slice(0, 5);
let currentSlotEndHour = currentSlot.slice(-5);
let nextSlotStartHour = nextSlot.slice(0, 5);
let nextSlotEndHour = nextSlot.slice(-5);
if (currentSlotEndHour === nextSlotStartHour) {
// merge slots
console.log(currentSlotStartHour);
console.log(currentSlotEndHour);
console.log(nextSlotStartHour);
console.log(nextSlotEndHour);
let compressedSlot = currentSlotStartHour
.concat(" - ")
.concat(nextSlotEndHour);
// add compressed slot
compressed.push(compressedSlot);
// remove the next slot
result.splice(i + 1, 1);
} else {
compressed.push(currentSlot);
}
}
}
console.log(compressed);
// compressed is: ["09:00 - 10:00", "10:00 - 11:00", "11:30 - 12:30", "12:30 - 13:00", "16:00 - 16:30"]
Thanks
Upvotes: 0
Views: 253
Reputation: 48630
The most basic algorithm is the following:
const slots = [
"09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00",
"11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00",
"16:00 - 16:30",
"17:00 - 17:30"
];
const optimizeTimeSlots = (slots, delimiter) => {
return slots.reduce((acc, slot) => {
if (acc.length === 0) {
acc.push(slot);
} else {
const curr = slot.split(delimiter);
const prev = acc[acc.length - 1].split(delimiter);
if (prev[1] !== curr[0]) {
acc.push(slot);
} else {
prev[1] = curr[1];
acc[acc.length - 1] = prev.join(delimiter);
}
}
return acc;
}, []);
}
console.log(optimizeTimeSlots(slots, ' - '));
.as-console-wrapper { top: 0; max-height: 100% !important; }
You can remove the main branching-logic by removing the following if (acc.length === 0) / else
clause and start your accumulator with [ slots.shift() ]
instead of an empty array.
You could modify this slightly, to make it look more ES6-ish...
const slots = [
"09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00",
"11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00",
"16:00 - 16:30",
"17:00 - 17:30"
];
const optimize = (arr, delim) =>
arr.reduce((acc, item) =>
(([cs, ce, ps, pe]) => pe !== cs
? [ ...acc, ...[[ps, pe], [cs, ce]].map(p => p.join(delim)) ]
: [ ...acc, [ ps, ce ].join(delim) ]
)([item, acc.pop()].map(p => p.split(delim)).flat()),
[ arr.shift() ]);
console.log(optimize(slots, ' - '));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Here is an optimized version that splits each slot once and recombines them at the very end. This is much harder to follow.
const slots = [
"09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00",
"11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00",
"16:00 - 16:30",
"17:00 - 17:30"
];
const optimize = (arr, delim) =>
arr.reduce((acc, item) =>
((prev, [ start, end ]) => prev.end !== start
? [ ...acc, prev, { start, end } ]
: [ ...acc, { start: prev.start, end } ]
)(acc.pop(), item.split(delim)),
[ (([start, end]) => ({ start, end }))
(arr.shift().split(delim)) ])
.map(obj => Object.values(obj).join(delim));
console.log(optimize(slots, ' - '));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Upvotes: 3
Reputation: 178094
I got held up before I could post
This version is using objects which are easier to use subsequently
const compressed = ["09:00 - 09:30", "09:30 - 10:00", "10:00 - 10:30", "10:30 - 11:00", "11:30 - 12:00", "12:00 - 12:30", "12:30 - 13:00", "16:00 - 16:30", "17:00 - 17:30"].reduce((acc, cur) => {
const [start, end] = cur.split(" - ");
if (acc.length) {
if (acc[acc.length - 1].end === start) acc[acc.length - 1].end = end;
else acc.push({ start, end });
} else acc.push({ start, end });
return acc;
}, [])
console.log(compressed)
Upvotes: 1