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 qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List as List
type Map = Map.Map
type Set = Set.Set
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 :: forall k. forall v. Ord k => (k -> [v]) -> Set k -> MultiMap k v
fromSet f s = MultiMap m (count m)
where
m :: Map k [v]
#if MIN_VERSION_containers(5,0,0)
m = Map.fromSet f s
#else
m = Map.fromList $ zip xs (map f xs)
xs = Set.toList s
#endif
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)