Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert into Data.Set and check if element exists at the same time

Tags:

haskell

Is there an efficient way to insert a value into a Data.Set while at the same time checking if that value was already a member of the set?

If there isn't, is there any particular reason such a function would be impossible to write with the current implementation of sets in the containers library?

like image 695
bennofs Avatar asked Sep 13 '14 20:09

bennofs


2 Answers

You can do this with O(log n) complexity by taking advantage of the fact that size is O(1), and just compare before and after:

-- | Inserts a value into the Set.  If the value was not already in the set,
-- | then True is returned, otherwise False
insertIfMissing :: Ord a => a -> Set a -> (Set a, Bool)
insertIfMissing a s = (newSet, missing)
    where
        newSet = Set.insert a s
        oldSize = Set.size s
        newSize = Set.size newSet
        missing = oldSize < newSize

And if you aren't interested in whether it was already present, then this shouldn't compute the missing part thanks to laziness.

like image 74
bheklilr Avatar answered Sep 29 '22 11:09

bheklilr


It is actually possible to write such a function by slightly changing the Set.insert function. I decided to return a Maybe (Set a), so the function only creates a new Set if the element did not alredy exist. It would be equally well possible to write a function with (Bool, Set a) as return type.

insertMember :: Ord a => a -> Set a -> Maybe (Set a)
insertMember = go
  where
    go :: Ord a => a -> Set a -> Maybe (Set a)
    STRICT_1_OF_2(go)
    go x Tip = Just $ singleton x
    go x (Bin sz y l r) = case compare x y of
        LT -> do 
           l' <- go x l
           return $ balanceL y l' r
        GT -> do 
           r' <- go x r
           return $ balanceR y l 
        EQ -> Nothing
like image 36
felix-eku Avatar answered Sep 29 '22 11:09

felix-eku