Murakami
Murakami

Reputation: 3760

Reduce method in JavaScript

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

Answers (5)

Scrimothy
Scrimothy

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

Doug Coburn
Doug Coburn

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

Mark
Mark

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

Taki
Taki

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

fubar
fubar

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

Related Questions