2010-10-20 54 views
10

我想合并两个地图,但没有内置加入集合的方法。你是怎么做到的?,如何合并2个Collections.Map实例?

+0

你应该看看这里(http://stackoverflow.com/questions/590991/merging-two-ienumerablets),基本上map1.Union(map2)应该工作 – dvhh 2010-10-20 04:44:47

+0

轻微的狡辩:使用linq的Union算子,你最终会一个IEnumerable元组,与地图不完全相同。 – Robert 2010-10-20 04:53:34

回答

6

定义下面的函数:

let join (p:Map<'a,'b>) (q:Map<'a,'b>) = 
    Map(Seq.concat [ (Map.toSeq p) ; (Map.toSeq q) ]) 

例如:

let a = Map([1,11;2,21;3,31;]) 

let b = Map([3,32; 4,41;5,51;6,61;]) 

let c = join a b 

和结果:

val c : Map<int,int> = 
    map [(1, 11); (2, 21); (3, 32); (4, 41); (5, 51); (6, 61)] 
+0

谢谢!这工作。 – klactose 2010-10-20 05:03:05

+1

请注意,这会重建从头开始的两个地图,这可能非常缓慢。如果'map1'很大,'map2'很小,一个更好的解决方案是Robert。 – 2014-01-23 15:06:07

20

您可以实现这一点使用Map.fold和Map.add,因为附加实际上是添加/替换:

let map1 = Map.ofList [ 1, "one"; 2, "two"; 3, "three" ] 
let map2 = Map.ofList [ 2, "two"; 3, "oranges"; 4, "four" ] 


let newMap = Map.fold (fun acc key value -> Map.add key value acc) map1 map2 

printfn "%A" newMap 

可能就是这个道理合并不提供开箱即用的是你需要处理与关键冲突。在这个简单的合并算法中,我们简单地从第二张图中取出关键值对,这可能不是您想要的行为。

+0

事实上,这正是我如何实现这一点: – Massif 2010-10-20 09:26:25

9

的另一种方法是这样的:

let merge (a : Map<'a, 'b>) (b : Map<'a, 'b>) (f : 'a -> 'b * 'b -> 'b) = 
    Map.fold (fun s k v -> 
     match Map.tryFind k s with 
     | Some v' -> Map.add k (f k (v, v')) s 
     | None -> Map.add k v s) a b 

它可以让你决定你想要什么值,如果有重复的键。

实施例:

let a = Map([1,11;2,21;3,31;]) 

let b = Map([3,32; 4,41;5,51;6,61;]) 

merge a b (fun k (v, v') -> v + v');; 

//Result 
val it : Map<int,int> = 
    map [(1, 11); (2, 21); (3, 63); (4, 41); (5, 51); (6, 61)] 

注意,关键3是不同的。

+0

注意:您实际上不需要指定输入参数的类型。 – Benjol 2013-02-05 10:38:18