有没有像数据结构那样的“可逆哈希表”?

时间:2018-04-29 13:02:04

标签: data-structures

想象一个关联数字和单词的数组。一个单词只有一个数字,反之亦然。

dic = [0: 'food', 
 1: 'dinner',
 2.5: 'breakfast',
  ...]

现在,我想访问dic[0]并获取foodsomething['food']并获取0。野外有任何可逆的哈希表吗?据我所知,只做副本可以解决这个问题。

1 个答案:

答案 0 :(得分:0)

是的,这通常是通过组合两张地图来完成的。修改有点棘手,因为它们必须保持一对一的规则。

让我们从有限地图的类开始,以及containers类型的几个示例实例:

{-# LANGUAGE
      FunctionalDependencies
    , FlexibleInstances
    , UndecidableInstances
    , GeneralizedNewtypeDeriving #-}

module Mappy where
import Prelude hiding (lookup)
-- Example base maps
import qualified Data.Map.Strict as M
import Data.Map (Map)
import qualified Data.IntMap.Strict as IM
import Data.IntMap (IntMap)

class Mappy k v m | m -> k v where
  empty :: m
  insert :: k -> v -> m -> m
  delete :: k -> m -> m
  lookup :: k -> m -> Maybe v

instance Ord k => Mappy k a (Map k a) where
  empty = M.empty
  insert = M.insert
  delete = M.delete
  lookup = M.lookup

instance Mappy Int a (IntMap a) where
  empty = IM.empty
  insert = IM.insert
  delete = IM.delete
  lookup = IM.lookup

现在我们可以为双向地图构建我们的类型:

data Bimap m n = Bimap !m !n
instance Show m => Show (Bimap m n) where
  showsPrec p (Bimap m _) = showParen (p > 10) $
    showString "Bimap " . showsPrec 11 m

invert :: Bimap m n -> Bimap n m
invert (Bimap m n) = Bimap n m

instance (Mappy k v kv, Mappy v k vk) => Mappy k v (Bimap kv vk) where
  empty = Bimap empty empty
  insert k v (Bimap kv vk)
    | Just k' <- lookup v vk
    = Bimap (insert k v $ delete k' kv) (insert v k vk)
    | otherwise
    = Bimap (insert k v kv) (insert v k vk)
  delete k m@(Bimap kv vk)
    | Just v <- lookup k kv
    = Bimap (delete k kv) (delete v vk)
    | otherwise
    = m
  lookup k (Bimap kv _) = lookup k kv

我们还可以定义一些包装器,以便更容易编写我们想要的地图类型。

newtype MapMap k v = MapMap (Bimap (Map k v) (Map v k)) deriving (Show, Mappy k v)
newtype IMM v = IMM (Bimap (IntMap v) (Map v Int)) deriving (Show, Mappy Int v)