As promised, here are some F# solutions to my second lunchtime LINQ challenge. I’ve still got a way to go with getting familiar with all the features of F#, so thanks especially to Sehnsucht whose answers pointed me in the direction of some better ways to solve these.

Problem 1 – Motorsport Scores

For the first one, I pretty much went with the same approach as in C#: convert to int, sort, skip 3, then sum:

``````let scores = "10,5,0,8,10,1,4,0,10,1"
scores.Split(',')
|> Seq.map int
|> Seq.sort
|> Seq.skip 3
|> Seq.sum
|> DumpAs "Q1"
``````

Problem 2 – Bishop Moves

My first attempt at this one used `Seq.collect`, which is the F# equivalent of LINQ’s `SelectMany`.

``````seq { 'A' ..'H' }
|> Seq.collect (fun a -> seq { 1 .. 8 } |> Seq.map (fun x -> sprintf "%c%d" a x))
|> Seq.filter (fun p -> abs (int p.[0] - int 'C') = abs (int p.[1] - int '6'))
|> Seq.filter (fun p -> p <> "C6")
|> String.concat ","
|> DumpAs "Q2"
``````

But in the C# solution we saw how the LINQ Query Expression Syntax makes for a cleaner way of expressing the problem that doesn’t repeat the starting position. And it turns out that we can create a very similar solution in F#:

``````seq {
for r in 1 .. 8 do
for c in 'a' .. 'h' do
let dx = abs (r - 6)
let dy = abs (int c - int 'c')
if dx <> 0 && dx = dy
then yield sprintf "%c%d" c r
}
|> DumpAs "Q2"
``````

Problem 3 – Sampling

This was one where F# surprisingly lacks the method that made it so easy in C#. F~ has a `mapi` function which gives an index of each item, but there is no corresponding `filteri` function (feature request here) . So I ended up using a `mapi` to create a sequence of tuples, which I could then filter and map back to a string.

``````let samples = "0,6,12,18,24,30,36,42,48,53,58,63,68,72,77,80,84,87,90,92,95,96,98,99,99,100,99,99,98,96,95,92,90,87,84,80,77,72,68,63,58,53,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,-30,-36,-42,-48,-53,-58,-63,-68,-72,-77,-80,-84,-87,-90,-92,-95,-96,-98,-99,-99,-100,-99,-99,-98,-96,-95,-92,-90,-87,-84,-80,-77,-72,-68,-63,-58,-53,-48,-42,-36,-30,-24,-18,-12,-6"
samples.Split(',')
|> Seq.mapi (fun a b -> a,(int b))
|> Seq.filter (fun x -> (fst x + 1) % 5 = 0)
|> Seq.map (snd >> (sprintf "%d"))
|> String.concat ","
|> DumpAs "Q3"
``````

Sehnsucht provided an interesting alternative approach, making use of `Seq.chunkBySize`:

``````"0,6,12,18,24,30,36,42,48,53,58,63,68,72,77,80,84,87,90,92,95,96,98,99,99,100,99,99,98,96,95,92,90,87,84,80,77,72,68,63,58,53,48,42,36,30,24,18,12,6,0,-6,-12,-18,-24,-30,-36,-42,-48,-53,-58,-63,-68,-72,-77,-80,-84,-87,-90,-92,-95,-96,-98,-99,-99,-100,-99,-99,-98,-96,-95,-92,-90,-87,-84,-80,-77,-72,-68,-63,-58,-53,-48,-42,-36,-30,-24,-18,-12,-6"
.Split(',')
|> Seq.chunkBySize 5
|> Seq.map (Array.item 4)
|> DumpAs "Q3"
``````

Problem 4 – Vote Winning Margin

This one was quite easy, as the `sumBy` function lets us use the same technique as with C# and turn yes into +1 and no into –1 and sum:

``````"Yes,Yes,No,Yes,No,Yes,No,No,No,Yes,Yes,Yes,Yes,No,Yes,No,No,Yes,Yes"
.Split(',')
|> Seq.sumBy (fun x -> if x = "Yes" then 1 else -1)
|> DumpAs "Q4"
``````

But again Sehnsucht pointed me in the direction of an alternative solution, and that is to use the `function` keyword (not the same as the `fun` keyword) which allows you to use pattern matching in the function definition. What I hadn’t realised was that you are not forced to match all possible inputs, and so you can do something like this:

``````"Yes,Yes,No,Yes,No,Yes,No,No,No,Yes,Yes,Yes,Yes,No,Yes,No,No,Yes,Yes"
.Split(',')
|> Seq.sumBy (function "Yes" -> 1 | "No" -> -1)
|> DumpAs "Q4"
``````

Problem 5 – Counting Pets

In C# we used `GroupBy`, but noted that a better solution would be if there was a method called `countBy`. And guess what, F# has one! And we can use the `function` keyword we just learned about to specify that we want to count dogs and cats separately but batch all other pets together. And I also learned another new F# function, the ‘destructuring’ operator `||>`, letting me pass a tuple to `sprintf` without needing to use `fst` and `snd` explicitly.

``````"Dog,Cat,Rabbit,Dog,Dog,Lizard,Cat,Cat,Dog,Rabbit,Guinea Pig,Dog"
.Split(',')
|> Seq.countBy (function x when x = "Dog" || x = "Cat" -> x | _ -> "Other")
|> Seq.map (fun x -> x ||> sprintf "%s:%d")
|> String.concat ","
|> DumpAs "Q5b"
``````

I have a feeling the `map` could be cleaned up even further with the composition operator `>>` but I couldn’t come up with the right syntax.

Problem 6 – Run Length Decoding

Finally, for this problem I took a very similar approach to C#, taking advantage of `Regex.Matches` and `Cast<Match>` to get started.

``````Regex.Matches("A5B10CD3",@"[A-Z]\d*")
.Cast<Match>()
|> Seq.map (fun m -> m.Value)
|> Seq.map (fun m -> new string(m.[0], if m.Length = 1 then 1 else int (m.Substring(1))))
|> String.concat ""
|> DumpAs "Q6"
``````

Of course, one of the things that F# makes really easy is to create little helper functions that you can use to simplify your code, in the same way that you might declare intermediate variables in C# to make your code more readable.

So for example we might create a `repeats` function to decide how many times a letter should be repeated, a `repeat` function to construct the string with that many repeats, and a `matches` function to simplify performing the regex. It doesn’t make the solution shorter, but I think this style of coding does aid readability:

``````let repeats (s:string) =
match s.Substring(1) with | "" -> 1 | n -> int n

let repeat c n = new string(c, n)

let matches input regex =
Regex.Matches(input,regex).Cast<Match>()
|> Seq.map (fun m -> m.Value)

matches "A5B10CD3" @"[A-Z]\d*"
|> Seq.map (fun m -> repeat m.[0] (repeats m))
|> String.concat ""
|> DumpAs "Q6"
``````

As always, I’d love to hear from any F# gurus in the comments if there are some cool tricks and techniques I’ve missed.

Want to learn more about LINQ? Be sure to check out my Pluralsight course More Effective LINQ.