0

I have to arrays of dates that look like this:

let slots = [|
  "2014-08-11T10:00:00-04:00",
  "2014-08-11T10:30:00-04:00",
  "2014-08-11T11:00:00-04:00",
  "2014-08-11T11:30:00-04:00",
  "2014-08-11T12:00:00-04:00",
  "2014-08-11T12:30:00-04:00",
  "2014-08-11T13:00:00-04:00"
|];
let badSlots = [|
  "2014-08-11T11:00:00-04:00",
  "2014-08-11T11:30:00-04:00",
  "2014-08-11T12:00:00-04:00",
|];

How would I remove items from the first array that appear in the second array so that the result is:

result [
  '2014-08-11T10:00:00-04:00',
  '2014-08-11T10:30:00-04:00',
  '2014-08-11T12:30:00-04:00',
  '2014-08-11T13:00:00-04:00'
]

So far I have tried this in reason which seems to finding the matches but the result format is all wrong.

let checkBool = s => Belt.Array.map(badSlots, bs => s !== bs);
let check = s =>
  Belt.Array.keepMap(badSlots, bs =>
    if (s !== bs) {
      Some(s);
    } else {
      None;
    }
  );
let checkBoolResult = Belt.Array.map(slots, s => checkBool(s));
Js.log2("checkBoolResult", checkBoolResult);
let checkResult = Belt.Array.keepMap(slots, s => Some(check(s)));
Js.log2("checkResult", checkResult);

Which logs:

checkBoolResult [
  [ true, true, true ],
  [ true, true, true ],
  [ false, true, true ],
  [ true, false, true ],
  [ true, true, false ],
  [ true, true, true ],
  [ true, true, true ]
]
checkResult [
  [
    '2014-08-11T10:00:00-04:00',
    '2014-08-11T10:00:00-04:00',
    '2014-08-11T10:00:00-04:00'
  ],
  [
    '2014-08-11T10:30:00-04:00',
    '2014-08-11T10:30:00-04:00',
    '2014-08-11T10:30:00-04:00'
  ],
  [ '2014-08-11T11:00:00-04:00', '2014-08-11T11:00:00-04:00' ],
  [ '2014-08-11T11:30:00-04:00', '2014-08-11T11:30:00-04:00' ],
  [ '2014-08-11T12:00:00-04:00', '2014-08-11T12:00:00-04:00' ],
  [
    '2014-08-11T12:30:00-04:00',
    '2014-08-11T12:30:00-04:00',
    '2014-08-11T12:30:00-04:00'
  ],
  [
    '2014-08-11T13:00:00-04:00',
    '2014-08-11T13:00:00-04:00',
    '2014-08-11T13:00:00-04:00'
  ]
]

Any guidance would be appreciated in either syntax. Thanks.

armand
  • 693
  • 9
  • 29

2 Answers2

1

Via the reason discord forum here:

This solution works:

let x = Js.Array.filter(x => !Array.mem(x, badSlots), slots);

//output
x [
  '2014-08-11T10:00:00-04:00',
  '2014-08-11T10:30:00-04:00',
  '2014-08-11T12:30:00-04:00',
  '2014-08-11T13:00:00-04:00'
]
armand
  • 693
  • 9
  • 29
0

The answer posted by armand works, but is inefficient. Where m and n are the lengths of the two arrays, this has O(m*n) runtime complexity.

In OCaml I would create a set for the "bad" slots from the given array. This enables logarithmic access rather than linear when checking for membership in the "bad" slots.

# let slots = [|
  "2014-08-11T10:00:00-04:00";
  "2014-08-11T10:30:00-04:00";
  "2014-08-11T11:00:00-04:00";
  "2014-08-11T11:30:00-04:00";
  "2014-08-11T12:00:00-04:00";
  "2014-08-11T12:30:00-04:00";
  "2014-08-11T13:00:00-04:00";
|]
let badSlots = [|
  "2014-08-11T11:00:00-04:00";
  "2014-08-11T11:30:00-04:00";
  "2014-08-11T12:00:00-04:00";
|];;
val slots : string array =
  [|"2014-08-11T10:00:00-04:00"; "2014-08-11T10:30:00-04:00";
    "2014-08-11T11:00:00-04:00"; "2014-08-11T11:30:00-04:00";
    "2014-08-11T12:00:00-04:00"; "2014-08-11T12:30:00-04:00";
    "2014-08-11T13:00:00-04:00"|]
val badSlots : string array =
  [|"2014-08-11T11:00:00-04:00"; "2014-08-11T11:30:00-04:00";
    "2014-08-11T12:00:00-04:00"|]
# let bad_slots_set = 
    badSlots 
    |> Array.to_seq 
    |> StringSet.of_seq;;
val bad_slots_set : StringSet.t = <abstr>
# let filtered_slots = 
    slots 
    |> Array.to_seq 
    |> Seq.filter (fun r -> not @@ StringSet.mem r bad_slots_set) 
    |> List.of_seq;;
val filtered_slots : string list =
  ["2014-08-11T10:00:00-04:00"; "2014-08-11T10:30:00-04:00";
   "2014-08-11T12:30:00-04:00"; "2014-08-11T13:00:00-04:00"]

This now has O(m*log(n)) runtime complexity.

Chris
  • 26,361
  • 5
  • 21
  • 42