Zipwith Kata Revisited

I went looking for mapi in C# and found it as an overload of LINQ Select. As I worked away, I got thinking about the Rangify kata we recently. One solution proposed for the Rangify kata used zipWith. I realized we could use mapi in place of the zipWiths for our kata.

Kata Recap: pretty print ranges. Given a list of sorted integers, consecutive values should be printed in a range. An example of [2, 3, 4, 5, 7, 9, 10, 11, 12, 15] would be printed as “2-5,7,9-12,15”. zipWith

The original solution using zipWiths was this:

let printRange (input : int list) =
    let zipWith fn xs ys = ys |> Seq.zip xs |> Seq.map (fun (x,y) -> fn x y)
    let display = function
        | [x]   -> string x
        | x::xs -> xs |> Seq.last |> sprintf "%d-%d" x

    input |> Seq.zip (zipWith (-) input { 1 .. System.Int32.MaxValue })
    |> Seq.groupBy fst
    |> Seq.map (snd >> Seq.map snd >> Seq.toList >> display)
    |> (fun ranges -> System.String.Join(",", ranges))

Using mapi we can re-write the solution to be:

let printRanges (input : int seq) =
    let display = function
      | [x]   -> string x
      | x::xs -> xs |> Seq.last |> sprintf "%d-%d" x

    input
    |> Seq.mapi (fun i x -> x - i, x)
    |> Seq.groupBy fst
    |> Seq.map (snd >> Seq.map snd >> Seq.toList >> display)
    |> (fun ranges -> System.String.Join(",", ranges))

Using mapi over zipWith removes some possible complexity in the solution. We no longer need to use multiple zipWiths as we can use the mapi index as the grouping modifier.

Avatar
Shane Charles
Software Developer

Related