@@ -42,9 +42,9 @@ module Streamly.Internal.Data.Stream.IsStream.Top
42 , leftJoin
42 , leftJoin
43 , mergeLeftJoin
43 , mergeLeftJoin
44 , hashLeftJoin
44 , hashLeftJoin
45− , outerJoin
45+ , joinOuter
46 , mergeOuterJoin
46 , mergeOuterJoin
47− , hashOuterJoin
47+ , joinOuterMap
@@ -385,7 +385,7 @@ leftJoin eq s1 s2 = Stream.evalStateT (return False) $ do
385 else Stream.nil
385 else Stream.nil
386 Nothing -> return (a, Nothing)
386 Nothing -> return (a, Nothing)
388−-- | Like 'outerJoin' but uses a hashmap for efficiency.
388+-- | Like 'joinOuter' but uses a hashmap for efficiency.
390-- Space: O(n)
390-- Space: O(n)
@@ -423,13 +423,13 @@ mergeLeftJoin _eq _s1 _s2 = undefined
423-- Time: O(m x n)
423-- Time: O(m x n)
425-- /Unimplemented/
425-- /Unimplemented/
426−{-# INLINE outerJoin #-}
426+{-# INLINE joinOuter #-}
427−outerJoin :: MonadIO m =>
427+joinOuter :: MonadIO m =>
428 (a -> b -> Bool)
428 (a -> b -> Bool)
429 -> SerialT m a
429 -> SerialT m a
430 -> SerialT m b
430 -> SerialT m b
431 -> SerialT m (Maybe a, Maybe b)
431 -> SerialT m (Maybe a, Maybe b)
432−outerJoin eq s1 s =
432+joinOuter eq s1 s =
433 Stream.concatM $ do
433 Stream.concatM $ do
434 arr <- Array.fromStream $ fmap (,False) s
434 arr <- Array.fromStream $ fmap (,False) s
435 return $ go arr <> leftOver arr
435 return $ go arr <> leftOver arr
@@ -470,7 +470,7 @@ outerJoin eq s1 s =
470-- a flag. At the end go through @t m b@ and find those that are not in that
470-- a flag. At the end go through @t m b@ and find those that are not in that
471-- hash to return (Nothing, b).
471-- hash to return (Nothing, b).
473−-- | Like 'outerJoin' but uses a hashmap for efficiency.
473+-- | Like 'joinOuter' but uses a hashmap for efficiency.
475-- For space efficiency use the smaller stream as the second stream.
475-- For space efficiency use the smaller stream as the second stream.
@@ -478,13 +478,38 @@ outerJoin eq s1 s =
479-- Time: O(m + n)
479-- Time: O(m + n)
481−-- /Unimplemented/
481+-- /Pre-release/
482−{-# INLINE hashOuterJoin #-}
482+{-# INLINE joinOuterMap #-}
483−hashOuterJoin :: -- (Monad m, Hashable b) =>
483+joinOuterMap ::
484− (a -> b -> Ordering) -> t m a -> t m b -> t m (Maybe a, Maybe b)
484+ (IsStream t, Ord k, MonadIO m) =>
485−hashOuterJoin _eq _s1 _s2 = undefined
485+ t m (k, a) -> t m (k, b) -> t m (k, Maybe a, Maybe b)
488+ km1 <- kvFold $ IsStream.adapt s1
489+ km2 <- kvFold $ IsStream.adapt s2
491+ let res1 = Stream.map (joinAB km2) s1
494+ case k `Map.lookup` km of
495+ Just b -> (k, Just a, Just b)
496+ Nothing -> (k, Just a, Nothing)
498+ let res2 = Stream.mapMaybe (joinAB km1) s2
501+ case k `Map.lookup` km of
503+ Nothing -> Just (k, Nothing, Just b)
505+ return $ Stream.serial res1 res2
509+ -- XXX Generate error if a duplicate insertion is attempted?
510+ kvFold = Stream.foldl' (\kv (k, b) -> Map.insert k b kv) Map.empty
487−-- | Like 'outerJoin' but works only on sorted streams.
512+-- | Like 'joinOuter' but works only on sorted streams.
489-- Space: O(1)
514-- Space: O(1)
@@ -607,7 +632,7 @@ mergeDifferenceBy _eq _s1 _s2 = undefined
607-- unionBy eq s1 s2 = s1 \`serial` (s2 `differenceBy eq` s1)
632-- unionBy eq s1 s2 = s1 \`serial` (s2 `differenceBy eq` s1)
610−-- Similar to 'outerJoin' but not the same.
635+-- Similar to 'joinOuter' but not the same.
612-- Space: O(n)
637-- Space: O(n)