{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Multimap.Generic (
Multimap(..), Group,
null, size, distinctSize,
empty, singleton,
#if __GLASGOW_HASKELL__ >= 708
fromList, inverse,
#endif
fromListWith, fromGroupList, fromMap,
member, notMember, count,
find, (!),
prepend, prependMany, append, appendMany,
deleteMany,
inverseWith,
filter, filterGroups,
mapGroups,
toList, toGroupList, toMap,
keys, keysSet, keysMultiset,
modifyMany, modifyManyF
) where
import Data.Multimap.Collection (Collection)
import qualified Data.Multimap.Collection as Col
import Data.Multiset (Multiset)
import qualified Data.Multiset as Mset
import Prelude hiding (filter, foldr, null)
import qualified Prelude as Prelude
import Data.Binary (Binary(..))
import Data.Foldable (foldl', foldr)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Data.Semigroup (Semigroup, (<>))
import Data.Set (Set)
import Data.Tuple (swap)
import qualified GHC.Exts
newtype Multimap c k v = Multimap
{ _toMap :: Map k (c v)
} deriving (Eq, Functor, Ord, Read, Show)
type Group k cv = (k, cv)
instance (Ord k, Semigroup (c v)) => Semigroup (Multimap c k v) where
Multimap m1 <> Multimap m2 = Multimap $ Map.unionWith (<>) m1 m2
instance (Ord k, Monoid (c v)) => Monoid (Multimap c k v) where
mempty = empty
instance Foldable c => Foldable (Multimap c k) where
foldr f r0 (Multimap m) = Map.foldr (\c r -> foldr f r c) r0 m
instance Traversable c => Traversable (Multimap c k) where
sequenceA (Multimap m) = Multimap <$> sequenceA (fmap sequenceA m)
instance (Binary k, Binary (c v)) => Binary (Multimap c k v) where
put (Multimap m) = put m
get = Multimap <$> get
#if __GLASGOW_HASKELL__ >= 708
instance (Collection c, GHC.Exts.IsList (c v), GHC.Exts.Item (c v) ~ v, Ord k) => GHC.Exts.IsList (Multimap c k v) where
type Item (Multimap c k v) = (k, v)
fromList = fromList
toList = toList
fromList
:: (Collection c, GHC.Exts.IsList (c v), GHC.Exts.Item (c v) ~ v, Ord k)
=> [(k, v)] -> Multimap c k v
fromList = fromListWith GHC.Exts.fromList
inverse
:: (Collection c, GHC.Exts.IsList (c k), GHC.Exts.Item (c k) ~ k, Ord k, Ord v)
=> Multimap c k v -> Multimap c v k
inverse = inverseWith GHC.Exts.fromList
#endif
null :: Multimap c k v -> Bool
null = Map.null . _toMap
size :: Collection c => Multimap c k v -> Int
size (Multimap m) = Map.foldl' (\n c -> n + Col.size c) 0 m
distinctSize :: Multimap c k v -> Int
distinctSize = Map.size . _toMap
empty :: Multimap c k v
empty = Multimap Map.empty
singleton :: Collection c => k -> v -> Multimap c k v
singleton k v = Multimap $ Map.singleton k (Col.singleton v)
fromGroupList :: (Collection c, Monoid (c v), Ord k) => [Group k (c v)] -> Multimap c k v
fromGroupList = fromMap . Map.fromListWith (<>)
fromListWith :: Ord k => ([v] -> c v) -> [(k, v)] -> Multimap c k v
fromListWith f ts = Multimap $ Map.map (f . reverse) $ m where
Multimap m = foldl' (\r (k, v) -> modifyMany (v:) k r) empty ts
fromMap :: Collection c => Map k (c v) -> Multimap c k v
fromMap = Multimap . Map.filter (not . Col.null)
find :: (Monoid (c v), Ord k) => k -> Multimap c k v -> c v
find k (Multimap m) = Map.findWithDefault mempty k m
(!) :: (Monoid (c v), Ord k) => Multimap c k v -> k -> c v
(!) = flip find
count :: (Collection c, Ord k) => k -> Multimap c k v -> Int
count k (Multimap m) = maybe 0 Col.size $ Map.lookup k m
member :: Ord k => k -> Multimap c k v -> Bool
member k = Map.member k . _toMap
notMember :: Ord k => k -> Multimap c k v -> Bool
notMember k = Map.notMember k . _toMap
modifyMany
:: (Collection c, Monoid (c v), Ord k)
=> (c v -> c v)
-> k
-> Multimap c k v
-> Multimap c k v
modifyMany f k (Multimap m) = Multimap $ Map.alter (wrap . f . unwrap) k m where
unwrap = fromMaybe mempty
wrap c = if Col.null c then Nothing else Just c
modifyManyF
:: (Collection c, Monoid (c v), Ord k, Functor f)
=> (c v -> f (c v))
-> k
-> Multimap c k v
-> f (Multimap c k v)
modifyManyF f k (Multimap m) = Multimap <$> Map.alterF (fmap wrap . f . unwrap) k m where
unwrap = fromMaybe mempty
wrap c = if Col.null c then Nothing else Just c
prepend :: (Collection c, Monoid (c v), Ord k) => k -> v -> Multimap c k v -> Multimap c k v
prepend k v = prependMany k (Col.singleton v)
prependMany :: (Collection c, Monoid (c v), Ord k) => k -> c v -> Multimap c k v -> Multimap c k v
prependMany k c = modifyMany (c <>) k
append :: (Collection c, Monoid (c v), Ord k) => k -> v -> Multimap c k v -> Multimap c k v
append k v = appendMany k (Col.singleton v)
appendMany :: (Collection c, Monoid (c v), Ord k) => k -> c v -> Multimap c k v -> Multimap c k v
appendMany k c = modifyMany (<> c) k
deleteMany :: Ord k => k -> Multimap c k v -> Multimap c k v
deleteMany k = Multimap . Map.delete k . _toMap
inverseWith :: (Collection c1, Ord k, Ord v) => ([k] -> c2 k) -> Multimap c1 k v -> Multimap c2 v k
inverseWith f = fromListWith f . fmap swap . toList
filter :: (Collection c, Monoid (c v), Ord k) => (v -> Bool) -> Multimap c k v -> Multimap c k v
filter f = fromGroupList . fmap (fmap (Col.filter f)) . toGroupList
filterGroups
:: (Collection c, Monoid (c v), Ord k)
=> (Group k (c v) -> Bool) -> Multimap c k v -> Multimap c k v
filterGroups f = fromGroupList . Prelude.filter f . toGroupList
mapGroups
:: (Collection c2, Monoid (c2 v2), Ord k2)
=> (Group k1 (c1 v1) -> Group k2 (c2 v2)) -> Multimap c1 k1 v1 -> Multimap c2 k2 v2
mapGroups f = fromGroupList . fmap f . toGroupList
toList :: Collection c => Multimap c k v -> [(k, v)]
toList (Multimap m) = concat $ fmap go $ Map.toList m where
go (k,c) = foldr (\v a -> (k,v) : a) [] c
toGroupList :: Multimap c k v -> [Group k (c v)]
toGroupList = Map.toList . _toMap
toMap :: Multimap c k v -> Map k (c v)
toMap = _toMap
keys :: Collection c => Multimap c k v -> [k]
keys (Multimap m) = Map.foldrWithKey go [] m where
go k c r = replicate (Col.size c) k <> r
keysSet :: Multimap c k v -> Set k
keysSet = Map.keysSet . _toMap
keysMultiset :: (Collection c, Ord k) => Multimap c k v -> Multiset k
keysMultiset = Mset.fromCountMap . Map.map Col.size . _toMap