Phil Trelford's Array
POKE 36879, 255

# Sorted with F# custom operators

January 21, 2010 01:39 by phil

F# lets you define your own operators, and like a man with a new hammer hunting for nails :) I’ve found an application of F# custom operators for sorting multiple columns:

`let inline (|?) a b = if a = 0 then b else a`

Lets start by trying to sort the table position of the current top 5 of English Football’s Premier League (compiled on 2010-01-21):

 Team Played Goal Difference Points Arsenal 22 34 48 Chelsea 21 34 48 Man Utd 22 30 47 Spurs 22 18 38 Man City 21 12 38

Lets say we represent the table as an array of tuples:

```let table = [|
("Arsenal", 22, 34, 48)
("Chelsea", 21, 34, 48)
("Spurs",   22, 18, 38)
("Man City",21, 12, 38)
("Man Utd", 22, 30, 47)
|] ```

If we could just sort on points, and wanted to sort the array in place, we could write:

`do  Array.Sort(table, fun (_,_,_,a) (_,_,_,b) -> b - a)   `

But as we can see from the table, some of the teams have the same points, so we need to order on points and goal difference. In the case of Arsenal and Chelsea at the top of the table, they not only have the same points, they have the same goal difference. In this situation the custom is to sort alphabetically (lucky for you if your team starts with the letter ‘A’).

The sort function must now apply secondary sorting criteria if the first expression gives zero:

```do  Array.Sort(table, fun a b ->
let nameA, _, gdA, pointsA = a
let nameB, _, gdB, pointsB = b
let points = pointsB - pointsA
let gd = gdB - gdA
let names = String.Compare(nameA, nameB)
if points <> 0 then points
else if gd <> 0 then gd
else names
)  ```

Now the custom operator introduced at the start of the article really captures it:

```do  Array.Sort(table, fun a b ->
let nameA, _, gdA, pointsA = a
let nameB, _, gdB, pointsB = b
pointsB - pointsA |? gdB - gdA |? String.Compare(nameA, nameB)
)  ```

The beauty of using the custom operator here, say over a function, is operators can be placed between expressions so can be used to compose the sort.

Finally, there are however a couple of other ways to hammer this nail:

• sort by mapping the table entry tuple
• using LINQ OrderBy and ThenBy

Mapping the table entry is easy on the eye but it does require the generation of temporary tuples and a new array:

`do  table |> Array.sortBy (fun (name,_,gd,points) -> -points,-gd,name) `

Using LINQ is also pretty easy on the eye but requires the generation of a new sequence:

```do  table.OrderByDescending(fun (_,_,_,p) -> p)
.ThenByDescending(fun (_,_,gd,_) -> gd)
.ThenBy(fun (name,_,_,_) -> name)```

PS If you are looking for a similar pattern in C#, Jon Skeet shows a similar (but more verbose) way of composing sort expressions using the ?? operator in his C# in Depth book.

PPS Tomas Petricek has a nice article with some sample use of custom operators in F#. Coincidentally he has just authored a book with Mr Skeet on Functional Programming.

PPPS For clarity I should point out that I am a Man Utd supporter, so the timing for this article could be seen as somewhat unfortunate.

Tags:
Categories: F#

January 21. 2010 10:21

I think a better option it's to sort by the played games, because if I played less games and have the same point I can obtain more points in the next match and not only sort by name in the case that I have the same points and the same Goal Average. Here is the code, need to change because the functions in F# changed for the Visual Studio Beta 2:

let s= table |> Array.sortWith (fun a b ->
let nameA, gpA, gdA, pointsA = a
let nameB, gpB, gdB, pointsB = b
pointsB - pointsA |? gdB - gdA |? gpA - gpB |? System.String.Compare(nameA, nameB))

January 22. 2010 00:37

Pingback from blog.cwa.me.uk

The Morning Brew - Chris Alcock  » The Morning Brew #523

January 29. 2010 11:16

F# Discoveries This Week 01/29/2010

Many apologies if I missed your post.  Having skipped last week due to some uncontrollable circumstances

May 20. 2010 11:44

Pingback from 291.codebluehacks.org

Parts 1998 I30 Ignition Coil Infiniti Fx45, 2004 Infiniti Fx45 Parts Used Car