Manipulating Collections in F# - Basic Examples
Tags: fsharp, beginners, dotnet, programming
Published: 2022-07-22 09:18:00

This article is to provide you with some basic examples of collection manipulation in `F#` run from a `console application` in `.NET 6`. The examples are drawn heavily from a series of exercises in `Stylish F# 6: Crafting Elegant Functional Code for .NET 6, 2nd Edition, 2021` by `Kit Eason`.

In order to run the examples you will need to add some initial utility functions and types to the top of your `program.fs` file.

```C#
type Car =
    { Model : string
      Price : decimal }
    
type PriceBand = | Cheap | Medium | Expensive

module FakeData =

    let private random = System.Random(Seed = 1)

    /// Make an array of 'count' number of random houses.
    let getRandomArrayOfCars (count: int) =
        Array.init count (fun i ->
            { Model = $"Model %i{i+1}"
              Price = random.Next(10_000, 150_000) |> decimal })
        
    /// Try to get the distance to the nearest garage.
    /// While the 'Car' parameter is not used we add it to change the signature
    /// Allowing us to pipe into it later with a Car object
    let tryGetDistanceToGarage (car: Car) =
        let dist = random.Next(30) |> double
        if dist < 20 then
            Some dist
        else
            None
            
    // Return a price band based on price.
    let getPriceCategory (price : decimal) =        
        if price < 40_000m then
            Cheap
        elif price < 100_000m then
            Medium
        else
            Expensive            

module Array =
    let inline tryAverageBy f (a : 'T[]) =
        if a.Length = 0 then
            None
        else
            let average = a |> Array.averageBy f |> decimal
            System.Math.Round(average, 2) |> Some
```

Then you can add the below examples and execute them with `dotnet run`.

```C#
// Transforming Data Items
let getCarListing =
    printfn "\n------ TRANSFORMING DATA ------" 
    FakeData.getRandomArrayOfCars 3
    |> Array.map (fun h ->
        printfn $"Model: {h.Model} - Price: {h.Price}")

// Calculating an Average
let getAverageCarPrice =
    printfn "\n-------- AVERAGE PRICE --------"
    let price = FakeData.getRandomArrayOfCars 10
                |> Array.averageBy (fun c -> c.Price)
    printfn $"Average price: {price}"
    
// Selecting Based on Condition, Order and iteration
let getExpensiveCars =
    printfn "\n------- EXPENSIVE CARS --------"
    FakeData.getRandomArrayOfCars 10
    |> Array.filter (fun c -> c.Price > 100_000m)
    |> Array.sortByDescending (fun c -> c.Price)
    |> Array.iter (fun c ->
        printfn $"Model: {c.Model} - Price: {c.Price}")

// Finding a Single Element
let getCarWithDistanceToGarage =
    printfn "\n- CAR WITH DISTANCE TO GARAGE -"
    let result = FakeData.getRandomArrayOfCars 1
                 |> Array.tryPick (fun c ->
                    match c |> FakeData.tryGetDistanceToGarage with
                    | Some d -> Some(c, d)
                    | None -> None)
    printfn $"{result}"

let getCarsByPriceCategory =
    printfn "\n--- CAR WITH PRICE CATEGORY ---"
    let result = FakeData.getRandomArrayOfCars 6
                 |> Array.groupBy (fun c -> c.Price |> FakeData.getPriceCategory)
                 |> Array.map (fun group ->
                    let category, cars = group
                    category, cars |> Array.sortBy (fun c -> c.Price))
    printfn $"{result[0]}"

let tryGetAverageCarPriceOver100K =
    printfn "\n--- AVERAGE PRICE OVER 100K ---"
    let result = FakeData.getRandomArrayOfCars 20
                 |> Array.filter (fun h -> h.Price > 100_000m)
                 |> Array.tryAverageBy (fun h -> h.Price)         
    printfn $"{result}"
```
**Output**
```config
------ TRANSFORMING DATA ------
Model: Model 1 - Price: 44813
Model: Model 2 - Price: 25504
Model: Model 3 - Price: 75381

-------- AVERAGE PRICE --------
Average price: 73004.4

------- EXPENSIVE CARS --------
Model: Model 1 - Price: 148567
Model: Model 8 - Price: 142968
Model: Model 6 - Price: 108595
Model: Model 7 - Price: 108251
Model: Model 2 - Price: 105497
Model: Model 3 - Price: 101684

- CAR WITH DISTANCE TO GARAGE -
Some(({ Model = "Model 1"
  Price = 63475M }, 15))

--- CAR WITH PRICE CATEGORY ---
(Cheap, Program+Car[])

--- AVERAGE PRICE OVER 100K ---
Some(120609.44)
```