F# dictionary entry grouping and sort issue

Answered F# dictionary entry grouping and sort issue

  • Saturday, March 02, 2013 6:54 PM
     
     

    Hello,

    let dNum = new Dictionary<int, decimal>()

    dNum.Add(0, 0M)

    dNum.Add(1, 10M)

    dNum.Add(2, 20M)

    dNum.Add(3, 30M)

    dNum.Add(4, 40M)

    dNum.Add(5, 30M)

    dNum.Add(6, 20M)

    I want to do this:

    Let’s divide the dictionary entries into groups of 3 consecutive entries, and check to see if the 3 entries are in ascending order or descending order, and if in ascending order, and if the first entry is less than the last entry by 10+, then create a new dictionary and add the entry as +1; and if in descending order, and if the first entry is more than the last entry by 10+, then create a new dictionary and add the entry as -1, otherwise, create a new dictionary and add the entry as 0.

    For example: in the above example: dNum entries: (1, 10M); (2, 20M); (3, 30M), then new dictionary:

    dNumSort.Add(1, 1)

    The final result for my example will be like this:

    let dNumSort = new Dictionary<int, int>()

    dNumSort.Add(0, 1)

    dNumSort.Add(1, 1)

    dNumSort.Add(2, 1)

    dNumSort.Add(3, 0)

    dNumSort.Add(4, -1)

    I think I can do this using non-functional way, but can’t figure out the functional way.

    To divide the dictionary entries into groups of 3 consecutive entries, I can use the following:

    let group3 = dNum

               |> Seq.map (fun (KeyValue(k,v)) -> v)

               |> Seq.windowed 3

    However, how to check to see if the group is in ascending or descending order and others seem not easy to put together.

    Any idea is welcome!

All Replies

  • Sunday, March 03, 2013 12:23 AM
     
     Answered Has Code

    It's a little ugly (not really overthought the thing) but seems correct

    open System.Collections.Generic
    
    let dNum = Dictionary (dict [ 0, 0M; 1, 10M; 2, 20M; 3, 30M; 4, 40M; 5, 30M; 6, 20M ])
    
    let result =
      Dictionary (
        dNum
        |> Seq.map (|KeyValue|)
        |> Seq.windowed 3
        |> Seq.map (fun arr ->
          let (k, v1), (_, v2), (_, v3) = arr.[0], arr.[1], arr.[2]
        // alternative for previous line but give a warning for incomplete match
        // but we know for sure the array has only 3 items
        //|> Seq.map (fun [| k, v1; _, v2; _, v3 |] ->
          k,
          if abs (v1 - v3) >= 10M then
            if v1 <= v2 && v2 <= v3 then 1
            elif v1 >= v2 && v2 >= v3 then -1
            else 0
          else 0)
        |> dict)


    Forgive my writing, English isn't my native language.

    • Marked As Answer by zydjohn Saturday, March 09, 2013 8:46 AM
    •  
  • Saturday, March 09, 2013 8:47 AM
     
     

    Thank you very much!

    Your code works!

    Thanks and have a nice weekend.

    John