David J Barnes
David J Barnes

Reputation: 506

Deduplicating arrays with datetime properties

The title of this question probably isn't totally appropriate and requires much more explanation. The problem: compare a list (array #1) of all time-slots with a list (array #2) of booked time-slots and return a list of available time-slots.

The arrays:

{
  "times": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T19:30:00.000Z"
    },
    {
      "start": "2017-05-11T19:30:00.000Z",
      "stop": "2017-05-11T20:00:00.000Z"
    },
    {
      "start": "2017-05-11T20:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    },
    {
      "start": "2017-05-11T20:30:00.000Z",
      "stop": "2017-05-11T21:00:00.000Z"
    },
    {
      "start": "2017-05-11T21:00:00.000Z",
      "stop": "2017-05-11T21:30:00.000Z"
    },
    {
      "start": "2017-05-11T21:30:00.000Z",
      "stop": "2017-05-11T22:00:00.000Z"
    }
  ],
  "booked": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    }
  ]
}

The expected and desired result would be:

{
      "start": "2017-05-11T20:30:00.000Z",
      "stop": "2017-05-11T21:00:00.000Z"
    },
    {
      "start": "2017-05-11T21:00:00.000Z",
      "stop": "2017-05-11T21:30:00.000Z"
    },
    {
      "start": "2017-05-11T21:30:00.000Z",
      "stop": "2017-05-11T22:00:00.000Z"
    }

I've solved similar problems in the past using map() or alasql but the difference is in the datetime comparison. Can someone point me in the right direction?

My current solution is in Node so I am looking for assistance using Node/JavaScript.

Upvotes: 0

Views: 54

Answers (3)

James
James

Reputation: 22237

A quick array.filter should do it:

var s = {
  "times": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T19:30:00.000Z"
    },
    {
      "start": "2017-05-11T19:30:00.000Z",
      "stop": "2017-05-11T20:00:00.000Z"
    },
    {
      "start": "2017-05-11T20:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    },
    {
      "start": "2017-05-11T20:30:00.000Z",
      "stop": "2017-05-11T21:00:00.000Z"
    },
    {
      "start": "2017-05-11T21:00:00.000Z",
      "stop": "2017-05-11T21:30:00.000Z"
    },
    {
      "start": "2017-05-11T21:30:00.000Z",
      "stop": "2017-05-11T22:00:00.000Z"
    }
  ],
  "booked": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    }
  ]
};
    
    var avail = s.times.filter(function (el) {
      for (var i = 0,b; b = s.booked[i]; i++) {
        if (el.start < b.stop && el.stop > b.start) return false;
      }
      return true;
    });
    
    console.log(avail);

Upvotes: 2

rpadovani
rpadovani

Reputation: 7360

Something like that should work

function isFree(time) {
   const tStart = time.start;
   const tStop = time.stop;
   
   // We order so if tStop < x.start we are sure no one of the following booking is overlapping
   const occupiedSlot = t.booked.sort((a, b) => b.start - a.start);
   
   for (let xx in occupiedSlot) {
     let x = occupiedSlot[xx]
     if (tStop < x.start) return true;
     
     if (tStart > x.stop) continue;
     
     if (tStart >= x.start && tStart < x.stop) return false;
     
     if (tStart <= x.start && tStop > x.start) return false;
   }
   
   return true;
}

const t = {
  "times": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T19:30:00.000Z"
    },
    {
      "start": "2017-05-11T19:30:00.000Z",
      "stop": "2017-05-11T20:00:00.000Z"
    },
    {
      "start": "2017-05-11T20:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    },
    {
      "start": "2017-05-11T20:30:00.000Z",
      "stop": "2017-05-11T21:00:00.000Z"
    },
    {
      "start": "2017-05-11T21:00:00.000Z",
      "stop": "2017-05-11T21:30:00.000Z"
    },
    {
      "start": "2017-05-11T21:30:00.000Z",
      "stop": "2017-05-11T22:00:00.000Z"
    }
  ],
  "booked": [
    {
      "start": "2017-05-11T19:00:00.000Z",
      "stop": "2017-05-11T20:30:00.000Z"
    }
  ]
}

const z = t.times.filter(isFree);
console.log(z)

Upvotes: 0

Soviut
Soviut

Reputation: 91525

Those are actually strings, not date objects, so you can compare them the way you would any string.

Javascript arrays have a .filter() method which has a similar interface to the .map() function. You give it a callback function and it spits out a new array where items from the original array are kept if the function returns true, and discards them if false.

var availableTimes = times.filter(function(time) {
  return booked.filter(function(book) {
    return book.start === time.start;
  }).length > 0;
});

Upvotes: 0

Related Questions