listocamlinterleave

How to interleave 3 lists in OCaml


I am trying to take three lists of strings and have the code return a list interleaving the three. If the lists have unequal sizes then we use "-" to indicate a value is missing.

For example:

interleave3 ["1"; "2"; "3"] ["4"] ["5"; "6"]

should return:

["1"; "4"; "5"; "2"; "-"; "6"; "3"; "-"; "-"]

Solution

  • If the task had been to just interleave the elements until all the lists are empty it would have been fairly straightforward; just rotate the lists while appending one element at a time until they're all empty.

    let rec interleave3 xs ys zs =
      match xs, ys, zs with
      | [], [], [] -> []
      | [], ys, zs -> "-" :: interleave3 ys zs []
      | x::xs, ys, zs -> x :: interleave3 ys zs xs
    

    However, since the requirement is that each list should effectively be padded out to equal length, we need to somehow keep track of how long the longest list is, and continue padding the resulting list until very list has been padded out. One way of doing so is to keep a total count, and continue going even after we're done, until the total is divisible by 3, at which point we know the resulting list has an equal number of elements:

    let interleave3 xs ys zs =
      let rec aux xs ys zs n =
        match xs, ys, zs with
        | [], [], [] when n mod 3 = 0 -> []
        | [], [], []    -> "-" :: aux [] [] [] (n+1)
        | [], ys, zs    -> "-" :: aux ys zs [] (n+1)
        | x::xs, ys, zs ->   x :: aux ys zs xs (n+1)
      in aux xs ys zs 0