Search code examples
f#list-manipulation

Join 2 list of recoreds based on same label in f#


I have 2 lists of records with one same label id1. I need a way to join them.

type A = { id1: int; name: string }

type B = { id1: int; id2: Option<int> }

let a1 = { id1 =  1; name = "nafis" }
let a2 = { id1 =  2; name = "habib" }

let b1 = { id1 = 1; id2 = Some(5) }
let b2 = { id1 = 1; id2 = None }
let b3 = { id1 = 2; id2 = None }

let a = [a1; a2]
let b = [b1; b2; b3]

printfn "%A" a =>  [({id1 = 1;name = "nafis";}, {id1 = 2;name = "habib";})]
printfn "%A" b =>  
[({id1 = 1; id2 = Some 5;}, {id1 = 1; id2 = None;}, {id1 = 2;id2 = None;})]

How can I join this 2 lists based on id1?

I want an output like this =>

[({id1 = 1;name = "nafis"; id2 = [Some 5; None];}, {id1 = 2;name = "habib"; id2 =[None];})]

Some form of tutorial or blog link will be helpful.


Solution

  • MSDN: Query expressions enable you to query a data source and put the data in a desired form. Query expressions provide support for LINQ in F#.

    As correctly mentioned in the comments, you need to have a third type C that will host the joined result and then use good old LINQ to join the lists:

    type A = { id1: int; name: string }
    type B = { id1: int; id2: Option<int> }
    type C = { id1: int; name: string; id2: Option<int> }
    
    let a1 = { id1 =  1; name = "nafis" }
    let a2 = { id1 =  2; name = "habib" }
    
    let b1 = { id1 = 1; id2 = Some(5) }
    let b2 = { id1 = 1; id2 = None }
    let b3 = { id1 = 2; id2 = None }
    
    let a = [a1; a2]
    let b = [b1; b2; b3]
    
    let result (a:A list) (b: B list) = query {
        for list1 in a do
        join list2 in b on
            (list1.id1 = list2.id1)
        select {id1 = list1.id1; name = list1.name; id2= list2.id2}
    }
    
    let c = result a b |> List.ofSeq
    

    Result:

    val c : C list = [{id1 = 1;
                   name = "nafis";
                   id2 = Some 5;}; {id1 = 1;
                                    name = "nafis";
                                    id2 = None;}; {id1 = 2;
                                                   name = "habib";
                                                   id2 = None;}]