0

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!

5
  • 3
    Can you post the code you tried Commented Jun 26, 2018 at 21:53
  • You're essentially wanting to check for equality. Could you not just convert both arrays to strings and compare the two? availableHours.join('') === exArr1.join('')? Commented Jun 26, 2018 at 21:55
  • @fubar no, the goal is to check if a day has been fully booked; or return true when no other appointments could be made for that day Commented Jun 26, 2018 at 21:57
  • Sorry, I mis-read the explanation. Commented Jun 26, 2018 at 21:58
  • Do you need to validate that exArr1 follows the rules of having hours next to each other? (ie fail somehow if [9, 11, 13]) Commented Jun 26, 2018 at 22:03

5 Answers 5

1

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));

Sign up to request clarification or add additional context in comments.

2 Comments

the .filter->.includes creates an exponential computation though. You can do this with a single loop
@user633183, agreed. I'd be interested to see how you can achieve it with a single loop, if you care to post answer or link to a demo fiddle.
0

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))

1 Comment

this answer doesn't return false when there are to unbooked consecutive hours. E.g. [11, 12, 13, 14] should return false, because [9, 10] can still be booked.
0

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)

Comments

0

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]));

Comments

0

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));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.