2015-10-06 106 views
3

如果我有2个哈斯克尔地图,例如:如何合并两张地图在Haskell

[("a",1), 
("b",2), 
("c",1)] 

[("a",1)] 

我怎么能以这样的方式,它将给写一个函数像这样:

[("a",2),("b",2),("c",1)] 

到现在为止我只能写基本情况,但那都是。

+3

看起来你'Data.Map'需要'unionWith':'unionWith(+)MAP1 map2'。 – ach

+0

如果您正在实施一个包,请考虑使用[multiset](http://hackage.haskell.org/package/multiset)包。 –

回答

9

如何unionWithData.Map

这里有两幅地图m1m2都包含密钥“A”使用它的样本GHCI会话:

Prelude> import qualified Data.Map as Map 
Prelude Data.Map> let m1 = Map.fromList [('a', 1)] 
Prelude Data.Map> let m2 = Map.fromList [('a', 2), ('b', 10)] 
Prelude Data.Map> Map.unionWith (+) m1 m2 
fromList [('a',3),('b',10)] 

如果要定义自己的功能来包装所有了:

mergeMap :: (Ord k, Num a) => Map.Map k a -> Map.Map k a -> Map.Map k a 
mergeMap = Map.unionWith (+) 

其是相同

mergeMap a b = Map.unionWith (+) a b 

甚至

a `mergeMap` b = Map.unionWith (+) a b 

,你也可以让你想GHC推断mapUnion的类型,但它会推断相同的类型。


注:在现实生活中,一定要做出,因此Data.Map.Strict.unionWithData.Map.Lazy.unionWith之间的懒惰和严格的地图之间的正确选择。

+0

非常感谢。如果函数看起来像这样:bagSum :: M.Map String Int - > M.Map String Int - > M.Map String Int bagSum b1 b2 = M.unionWith(+)b1 b2 –

+0

我编辑了回答这个答案。 –

+0

并且应该调用mergeMap [(“a”,1),(“b”,2)] [(“a”,1),(“b”,2)] ???它说它不能绑定变量 –

2

Map的替代方案是sort。此版本假定每个键在每个列表中只出现一次。如果情况并非如此,你可以修复它,但Map方法将开始看起来更有吸引力。

combine op xs ys = cs op (s xs) (s ys) 
    where 
    s = sortBy (compare `on` fst) 

    cs _ [] qs = qs 
    cs _ ps [] = ps 
    cs op [email protected]([email protected](pk,pv):ps) [email protected]([email protected](qk,qv):qs) = 
     case compare pk qk of 
     LT -> p : cs op ps qss 
     GT -> q : cs op pss qs 
     EQ -> (pk, pv `op` qv) : cs op ps qs 
+0

我认为重复键是重点。 –

+0

@ErikAllik,当然有点难以确定 - 我们从一个例子来推理。我想象这些列表是为了代表地图,而且他们只需要合并。他们甚至可能已经被排序了。 – dfeuer