DEV Community

Rob
Rob

Posted on • Edited on

1 1

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

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more