Advent of Code: A Learning Journey in F# Day 1

Join a journey through Advent of Code challenges using F#. This article covers the first day's challenge, exploring functional programming concepts and solutions.

1 décembre 2024

Published

Hugo Mufraggi

Author

6 min read
Advent of Code: A Learning Journey in F# Day 1

A Learning Journey In F # Day 1

Advent of Code: A Learning Journey in F# Day 1

Every December, a programming challenge emerges that makes the hearts of coding enthusiasts race: Advent of Code. This year, I’ve decided to take on the challenge of using F#, a functional programming language that pushes me out of my comfort zone. As a developer who is not yet an F# expert, I believe this challenge is a unique opportunity for growth. Each problem is an invitation to explore the subtleties of functional programming, to push my boundaries, and to deepen my understanding of this fascinating language. My goal? To solve one problem per day and share my journey through a series of articles. Each solution will be more than just a piece of code — a learning narrative showcasing my thoughts, challenges, and discoveries throughout this wintry programming adventure. Join me as I navigate through algorithmic puzzles, learning F# one problem at a time, and documenting my progress day by day!

Day 1

You can retrieve the subject of day one [here](https://adventofcode.com/2024/day/1).

Part 1

Subject

For example:

3   4
4   3
2   5
1   3
3   9
3   3
Maybe the lists are only off by a small amount! To find out, pair up the numbers and measure how far apart they are. Pair up the smallest number in the left list with the smallest number in the right list, then the second-smallest left number with the second-smallest right number, and so on.

Within each pair, figure out how far apart the two numbers are; you'll need to add up all of those distances. For example, if you pair up a 3 from the left list with a 7 from the right list, the distance apart is 4; if you pair up a 9 with a 3, the distance apart is 6.

In the example list above, the pairs and distances would be as follows:

The smallest number in the left list is 1, and the smallest number in the right list is 3. The distance between them is 2.
The second-smallest number in the left list is 2, and the second-smallest number in the right list is another 3. The distance between them is 1.
The third-smallest number in both lists is 3, so the distance between them is 0.
The next numbers to pair up are 3 and 4, a distance of 1.
The fifth-smallest numbers in each list are 3 and 5, a distance of 2.
Finally, the largest number in the left list is 4, while the largest number in the right list is 9; these are a distance 5 apart.
To find the total distance between the left list and the right list, add up the distances between all of the pairs you found. In the example above, this is 2 + 1 + 0 + 1 + 2 + 5, a total distance of 11!

Your actual left and right lists contain many location IDs. What is the total distance between your lists?

To be simple, we have an input file with two lists of numbers separated by ``We need to :

  • Read the file input.
  • Extract the left and right list
  • Sort each by ascending ordering
  • Zip the two list
  • Iterate on each pair and du a substation
  • Iterate on the result and do a sum

Read file

First, I start by making a function to read a File from a path and return a list of strings.

open System.IO
let readFile path =
  seq { use reader = new StreamReader(File.OpenRead(path))
        while not reader.EndOfStream do
            yield reader.ReadLine()
      }

Cleaning input

I create a new function, and my function takes a string sequence. I iterate on each element, and for each, I do the following:

  • I split in ””
  • I trim the parasite space
  • And I create a tuple of int
  • I finish by converting my seq into a list
let cleanInput (input: string seq) =
    input
      |> Seq.map (fun line -> line.Split("  ")
      |> Array.map (fun word -> word.Trim())
      |> fun words -> (words.[0] |> int, words.[1] |> int))
      |> Seq.toList

Logic

[<EntryPoint>]
let main argv =
    let  rawList: (int * int) list = @"/Users/hugomufraggi/RiderProjects/ConsoleApp3/input.txt"
      |> readFile
      |> cleanInput
    
    let (left, right ) = List.unzip  rawList
    let leftSorted: int list = left |> List.sort
    let rightSorted: int list = right |> List.sort
    let res = step1 leftSorted rightSorted
    
    printfn "%A" res
    0

I unzip the rawList; the raw list is a list of tuples with a will obtain one list for my left column and my right column.

I sort each list and apply the logic of each step 1.

In step 1, I submit each element and sum result.

And I finish by printing the result.

let step1 leftSorted rightSorted =
  List.zip leftSorted rightSorted
    |> List.map (fun (l, r) -> abs (l - r))
    |> List.sum

Part 2

Subject

Here are the same example lists again:

3   4
4   3
2   5
1   3
3   9
3   3
For these example lists, here is the process of finding the similarity score:

The first number in the left list is 3. It appears in the right list three times, so the similarity score increases by 3 * 3 = 9.
The second number in the left list is 4. It appears in the right list once, so the similarity score increases by 4 * 1 = 4.
The third number in the left list is 2. It does not appear in the right list, so the similarity score does not increase (2 * 0 = 0).
The fourth number, 1, also does not appear in the right list.
The fifth number, 3, appears in the right list three times; the similarity score increases by 9.
The last number, 3, appears in the right list three times; the similarity score again increases by 9.
So, for these example lists, the similarity score at the end of this process is 31 (9 + 4 + 0 + 0 + 9 + 9).

Once again consider your left and right lists. What is their similarity score?

In step 2 we take the same input file we need to :

  • Read the file input.
  • Extract the left and right list.
  • In the Right list, count the number of occurrences for each element
  • Iterate on the left list and multiply the element by the number of occurrences of the right list
  • Sum the result

Logic

[<EntryPoint>]
let main argv =
let  rawList: (int * int) list = @"/Users/hugomufraggi/RiderProjects/ConsoleApp3/input.txt"
  |> readFile
  |> cleanInput
  

let (left, right ) = List.unzip  rawList
let res2 = step2 left right
printfn "%A" res2

All the logic is in my step2 function.

let extractMatch (rightMap: System.Collections.Generic.IDictionary< 'a,int>) number =
  match rightMap.TryGetValue(number) with
  | true, value -> value
  | false, _ -> 0

let step2 left right =
let rightMap = right
  |> List.countBy id
  |> Map.ofList
left
  |> List.map(fun (number) ->
    number * (extractMatch rightMap number))
  |> List.sum

I start by creating a hashmap of numbers and counts; it is the 3 first line.

I finish by returning the left. I iterate on each element and try to extract from my hashmap the number of occurrences for the element.

Inside extractMatch, I use a pattern matching the function .TryGetValue to return a boolean value. With this thing, I manage the case where TrygetValue retrieves or does not have a value.

Conclusion

This first day of Advent of Code in F# has been an excellent starting point for my learning journey. Each problem is an opportunity for growth, discovery, and personal challenge in the fascinating world of functional programming.

My commitment is clear: maintaining the rhythm and publishing my solutions and reflections daily. I strive to document every step, every difficulty, and every learning moment throughout this challenge. My goal is not perfection, but continuous progression.

To all developers, code enthusiasts, and curious readers: I invite you to follow me on this adventure. The Advent of Code challenges are more than just programming exercises — they are learning, self-improvement, and sharing opportunities.

I strongly encourage you to subscribe to my newsletter to ensure you don’t miss a single step of this journey. Each day, receive my detailed article in your inbox explaining my solution, thoughts, and discoveries in F#.

Together, let’s take on this challenge, learn, and grow! See you tomorrow for the next stage of Advent of Code.