0
\$\begingroup\$

I've been experimenting with the F# Bolero environment to learn F# a bit and I was trying to get the hang of pattern matching by generating ordinal numbers (1st, 2nd, 3rd, ...) from cardinal numbers (1, 2, 3, ...).

Here's the code I came up with:

let ordinal n =
    if n > 20 then
        match n % 10 with
        | 1 -> string n + "st"
        | 2 -> string n + "nd" 
        | 3 -> string n + "rd"
        | _ -> string n + "th"
    else
        match n % 20 with
        | 1 -> string n + "st"
        | 2 -> string n + "nd"
        | 3 -> string n + "rd"
        | _ -> string n + "th"

let hundred = [1..100]
let hundredOrdinals = List.map ordinal hundred

printfn "First %d ordinals:\n%A" hundred.Length hundredOrdinals

Which I believe produces the right ordinal numbers both for numbers less than and numbers greater than or equal to 20.

However, the patterns that are matched are identical for both branches of the if statement: both match an input of 1 to an output with "st", and input of 2 to an output with "nd" and so on, so I was wondering if I couldn't somehow recycle the matching criteria while keeping the matching expressions (n % 20 and n % 10). Any alternative approaches are also welcome.

Here's the output of the snippet above just in case it might contain errors, I've aligned some of the values to make it more readable.

First 100 ordinals:
[ "1st";  "2nd";  "3rd";  "4th";  "5th";  "6th";  "7th";  "8th";  "9th"; "10th";
 "11th"; "12th"; "13th"; "14th"; "15th"; "16th"; "17th"; "18th"; "19th"; "20th";
 "21st"; "22nd"; "23rd"; "24th"; "25th"; "26th"; "27th"; "28th"; "29th"; "30th";
 "31st"; "32nd"; "33rd"; "34th"; "35th"; "36th"; "37th"; "38th"; "39th"; "40th";
 "41st"; "42nd"; "43rd"; "44th"; "45th"; "46th"; "47th"; "48th"; "49th"; "50th";
 "51st"; "52nd"; "53rd"; "54th"; "55th"; "56th"; "57th"; "58th"; "59th"; "60th";
 "61st"; "62nd"; "63rd"; "64th"; "65th"; "66th"; "67th"; "68th"; "69th"; "70th";
 "71st"; "72nd"; "73rd"; "74th"; "75th"; "76th"; "77th"; "78th"; "79th"; "80th";
 "81st"; "82nd"; "83rd"; "84th"; "85th"; "86th"; "87th"; "88th"; "89th"; "90th";
 "91st"; "92nd"; "93rd"; "94th"; "95th"; "96th"; "97th"; "98th"; "99th"; "100th" ]
\$\endgroup\$
0
\$\begingroup\$

You can combine both cases with an if .. then .. else ..

let ordinal n =
    match if n > 20 then n % 10 else n % 20 with
    | 1 -> string n + "st"
    | 2 -> string n + "nd"
    | 3 -> string n + "rd"
    | _ -> string n + "th"
\$\endgroup\$
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.