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 zipWith
s 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 zipWith
s 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 zipWith
s as we can use the mapi
index as the grouping modifier.