DEV Community

Rob
Rob

Posted on • Edited on

Manipulating Collections in F# - Basic Examples

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.

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
Enter fullscreen mode Exit fullscreen mode

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

// 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}"
Enter fullscreen mode Exit fullscreen mode

Output

------ 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)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)