2015-10-06 109 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