module Hydrogen.MultiMap (
MultiMap
, empty
, null
, keys
, elems
, numKeys
, numElems
, lookup
, member
, insert
, delete
, update
, adjust
, toMap
, fromMap
, fromList
, fromList'
, fromSet
, toList
, toList'
, union
) where
import Prelude hiding (lookup, foldr, null)
import Data.Foldable (Foldable, foldr)
import Data.Traversable (Traversable)
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Map as Map
import qualified Data.List as List
data MultiMap k v = MultiMap (Map k [v]) Int
deriving (Eq, Ord, Functor, Foldable, Traversable, Generic, Typeable)
instance (Show k, Show v) => Show (MultiMap k v) where
show (MultiMap m _) = show m
count :: Map k [v] -> Int
count = foldr (\vs s -> length vs + s) 0
empty :: MultiMap k v
empty = MultiMap Map.empty 0
numKeys :: MultiMap k v -> Int
numKeys (MultiMap m _) = Map.size m
numElems :: MultiMap k v -> Int
numElems (MultiMap _ s) = s
null :: MultiMap k v -> Bool
null (MultiMap m _) = Map.null m
keys :: MultiMap k v -> [k]
keys (MultiMap m _) = Map.keys m
elems :: MultiMap k v -> [[v]]
elems (MultiMap m _) = Map.elems m
lookup :: Ord k => k -> MultiMap k v -> [v]
lookup k (MultiMap m _) = maybe [] id $ Map.lookup k m
member :: Ord k => k -> MultiMap k v -> Bool
member k = not . List.null . lookup k
insert :: Ord k => k -> v -> MultiMap k v -> MultiMap k v
insert k v mm@(MultiMap m s) = MultiMap (Map.insert k set' m) s'
where
set = lookup k mm
set' = v : set
s' = s length set + length set'
delete :: Ord k => k -> MultiMap k v -> MultiMap k v
delete k mm@(MultiMap m s) = MultiMap (Map.delete k m) s'
where
s' = s length (lookup k mm)
update :: Ord k => k -> [v] -> MultiMap k v -> MultiMap k v
update k vs mm@(MultiMap m s)
| List.null vs = MultiMap (Map.delete k m) s'
| otherwise = MultiMap (Map.insert k vs m) s'
where
s' = s length (lookup k mm) + length vs
adjust :: Ord k => ([v] -> [v]) -> k -> MultiMap k v -> MultiMap k v
adjust f k mm@(MultiMap m s)
| List.null set' = MultiMap (Map.delete k m) s'
| otherwise = MultiMap (Map.insert k set' m) s'
where
set = lookup k mm
set' = f set
s' = s length set + length set'
toMap :: MultiMap k v -> Map k [v]
toMap (MultiMap m _) = m
fromMap :: Map k [v] -> MultiMap k v
fromMap m = MultiMap m (count m)
toList :: MultiMap k v -> [(k, [v])]
toList (MultiMap m _) = Map.toList m
toList' :: MultiMap k v -> [(k, v)]
toList' = concat . map (\(k, vs) -> [(k, v) | v <- vs]) . toList
fromList :: Ord k => [(k, [v])] -> MultiMap k v
fromList xs = MultiMap (Map.fromList xs) (foldr (\x s -> length (snd x) + s) 0 xs)
fromList' :: Ord k => [(k, v)] -> MultiMap k v
fromList' = foldr (uncurry insert) empty
fromSet :: Ord k => (k -> [v]) -> Set k -> MultiMap k v
fromSet f s = MultiMap m (count m)
where
m = Map.fromSet f s
union :: Ord k => MultiMap k v -> MultiMap k v -> MultiMap k v
union (MultiMap m1 s1) (MultiMap m2 s2) = MultiMap (Map.unionWith (++) m1 m2) (s1 + s2)