Reputation: 3760
I guess it is more a logical problem, but it also concerns reduce method (I guess it is a proper method to that kind of issue).
Here are my 3 arrays:
const availableHours = [ 9, 10, 11, 12, 13, 14 ];
const exArr1 = [ 9, 10, 11, 12, 13, 14 ]
const exArr2 = [ 10, 11, 12, 13 ]
The first one represents all available hours. The user always books two of them, being next to each other (f.ex. 9and10, 13and14, 10and11, and so on...) in any configuration. Now, if user books all three sets (i.e. 9-10, 11-12, 13-14) I need to return true. It means the day is full booked. But also if it is booked f.ex. like that 10-11 and 12-13 it also should return true, as those hours which have been left unbooked (9 and 14) cannot be booked as they are single hours. Both example arrays should return true.
Can you help on that one? I tried to do that with reduce method but could not do that.
Thank you!
Upvotes: 0
Views: 122
Reputation: 2536
This doesn't use reduce either, but it does filter things properly, and I particularly like separating functions out for more readable/segmented code, rather than pushing all logic into one reducer.
const allAvailable = {
9: true,
10: true,
11: true,
12: true,
13: true,
14: true,
};
const exArr1 = [ 9, 10, 11, 12, 13, 14 ];
const exArr2 = [ 10, 11, 12, 13 ];
const exArr3 = [ 10, 11 ];
function remainingHours(hours) {
const stillAvailable = Object.assign({}, allAvailable);
hours.forEach(hour => {
delete stillAvailable[hour];
});
return Object.keys(stillAvailable);
}
function hasConsecutive(hoursAvailable) {
if (hoursAvailable.length < 2) {
return false;
}
return hoursAvailable.some((hour, index) => {
if (index < hoursAvailable.length - 1) {
return +hour + 1 === +hoursAvailable[index + 1];
}
});
}
function isBooked(hours) {
return !hasConsecutive(remainingHours(hours));
}
console.log(isBooked(exArr1));
console.log(isBooked(exArr2));
console.log(isBooked(exArr3));
Upvotes: 0
Reputation: 2575
In case you want to use Array.prototype.reduce
Here is a solution defined in a more functional manner.
const fullyBooked = (available, booked) =>
!booked.reduce(
// reducer zeros out booked hours from inverted array
(accumulator, currentValue) => (accumulator[currentValue] = 0, accumulator),
// initial value is available times inverted into an array of 1's and 0's 1 if available
available.reduce(
(accumulator2, currentValue2) => (accumulator2[currentValue2] = 1, accumulator2),
new Array(25).fill(0)
)
).some(
// not fully booked if two hours are sequentially available
(value, index, array) => value && array[index+1]
);
console.log(fullyBooked([9, 10, 11, 12, 13, 14], [9, 10, 11, 12, 13, 14]));
console.log(fullyBooked([9, 10, 11, 12, 13, 14], [9, 10, 11, 12, 13]));
console.log(fullyBooked([9, 10, 11, 12, 13, 14], [10, 11, 12, 13, 14]));
console.log(fullyBooked([9, 10, 11, 12, 13, 14], [9, 10, 13, 14]));
console.log(fullyBooked([9, 10, 11, 12, 13, 14], [9, 11]));
Upvotes: 0
Reputation: 92440
You can use filter to find the blocks you need with something like:
const availableHours = [ 9, 10, 11, 12, 13, 14 ];
const exArr1 = [ 9, 10, 11, 12, 13, 14 ]
const exArr2 = [ 11, 12 ]
function getStartTimes(arr, taken) {
return arr.filter((item, index) => index != availableHours.length -1
&& !taken.includes(item)
&& !taken.includes(availableHours[index +1])
)
}
console.log(getStartTimes(availableHours, exArr1))
console.log(getStartTimes(availableHours, exArr2))
The returned array will be hours which can start 2-hour blocks. You can test the length of this array if you just want true or false.
This also has the advantage that it will still work if one hour blocks are reserved like [9, 12, 13, 14]
(result should show a two hour block starting at 10 available)
Upvotes: 0
Reputation: 17654
you can use includes and filter the array that contains the available hours and return the difference :
const availableHours = [9, 10, 11, 12, 13, 14];
const exArr1 = [9, 10, 11, 12, 13, 14]
const exArr2 = [10, 11, 12, 13]
const check = (arr, avail) => {
const diff = avail.filter(e => !arr.includes(e))
if (diff.length === 0)
console.log('all hours are booked')
else
console.log('unbooked hours : ', diff)
return true
}
console.log(check(exArr1, availableHours))
console.log(check(exArr2, availableHours))
Upvotes: 0
Reputation: 17378
This answer doesn't use Array.prototype.reduce
, but I think it solves your problem.
It works by first removing any booked hours from the list of available hours. This assumes that the days bookings are correct (consecutively booked hourly pairs).
It then iterates through the remaining available hours and checks for consecutive hourly pairs. If none are found, the day is considered fully booked. If one or more is found, it isn't fully booked.
const available = [ 9, 10, 11, 12, 13, 14 ];
const day1 = [ 9, 10, 11, 12, 13, 14 ];
const day2 = [ 10, 11, 12, 13 ];
const day3 = [ 9, 10, 12, 13 ];
const day4 = [ 9, 10 ];
function isFullyBooked(day, available) {
const remaining = available.filter((hour) => ! day.includes(hour));
for (let i = 0; i < remaining.length; i++) {
if (remaining[i] + 1 === remaining[i + 1]) return false;
}
return true;
}
console.log(isFullyBooked(day1, available));
console.log(isFullyBooked(day2, available));
console.log(isFullyBooked(day3, available));
console.log(isFullyBooked(day4, available));
Upvotes: 1