如何在Haskell中合并2个地图

时间:2015-10-06 17:46:42

标签: haskell dictionary

如果我有2个Haskell地图,例如:

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

[("a",1)]

如何以这样的方式编写函数:

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

到目前为止,我只能编写基本案例,但这就是全部。

2 个答案:

答案 0 :(得分:12)

来自Data.MapunionWith怎么样?

以下是在两个地图m1m2上使用它的GHCi会话示例,其中包含密钥“a”:

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之间做出正确的选择。

答案 1 :(得分: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 pss@(p@(pk,pv):ps) qss@(q@(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