Search code examples
dictionaryf#nested-setshigher-order-functions

Invert nested dictionaries in f# Map<'a,Map<'b,'T>>) -> Map<'b,Map<'a,'T>>


I have a nested dictionary Map<'a,Map<'b,'T>>, so that for a combination of a*b, the entry is unique.

In order to precompute efficiently, I would need to invert the keys in a Map<'b,Map<'a,'T>>

I have some higher order methods that do the job (|/> will apply the operation in a nested sequence |//> the same, but 2 levels deep, |*> will enumerate the cartesian product of nested sequence), but I am wondering if there is a better way to do this, just in case there is beautiful code to share on this one.

let reversenmap (x:Map<'a,Map<'b,'T>>) :Map<'b,Map<'a,'T>> = 
      let ret  = x |> Map.toSeq |/> Map.toSeq |*> squash12
      let ret2 = ret |> Seq.groupByn2 (fun (a,b,t) -> b) 
                                      (fun (a,b,t) -> a) |//> Seq.head 
                                                         |//> (fun (a,b,c) -> c)
      ret2 |> Seq.toMapn2

Solution

  • I think the solution from @pad is definitely more idiomatic F# than using non-standard operators like |/> and |*>. I would probably prefer a version that uses sequence expressions instead of Seq.collect, which looks like this (the second part is the same as in the version from @pad):

    let reverse (map: Map<'a,Map<'b,'T>>) = 
      [ for (KeyValue(a, m)) in map do
          for (KeyValue(b, v)) in m do yield b, (a, v) ]
      |> Seq.groupBy fst 
      |> Seq.map (fun (b, ats) -> b, ats |> Seq.map snd |> Map.ofSeq) 
      |> Map.ofSeq