If I have 2 Haskell Maps, for example:
[("a",1),
("b",2),
("c",1)]
and
[("a",1)]
How can I write a function in such a way that it would give something like:
[("a",2),("b",2),("c",1)]
Until now I could only write the base cases but that was all.
How about unionWith
from Data.Map
?
Here's a sample GHCi session using it on two maps m1
and m2
both containing the key '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)]
If you want to define your own function to wrap all that up:
mergeMap :: (Ord k, Num a) => Map.Map k a -> Map.Map k a -> Map.Map k a
mergeMap = Map.unionWith (+)
which is the same as
mergeMap a b = Map.unionWith (+) a b
or even
a `mergeMap` b = Map.unionWith (+) a b
Note: in real life, make sure to make the right choice between lazy and strict maps, and hence between Data.Map.Strict.unionWith
and Data.Map.Lazy.unionWith
.
An alternative to Map
is sort
. This version assumes each key occurs only once in each list. If that's not the case, you could fix it up, but the Map
approach would start looking a lot more attractive.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With