on master help sign in
Refactor "nub", rename it to "frequency"
0f951fbHarendra Kumar
core/src/Streamly/Internal/Data/Fold/Window.hs+32−31
@@ -35,7 +35,6 @@ module Streamly.Internal.Data.Fold.Window
35 --
35 --
36 lmap
36 lmap
37 , cumulative
37 , cumulative
38− , nub
39
38
40 -- ** Sums
39 -- ** Sums
41 , length
40 , length
@@ -49,6 +48,9 @@ module Streamly.Internal.Data.Fold.Window
49 , maximum
48 , maximum
50 , range
49 , range
51 , mean
50 , mean
51+
52+ -- ** Distribution
53+ , frequency
52 )
54 )
53where
55where
54
56
@@ -66,10 +68,12 @@ import qualified Streamly.Internal.Data.Ring.Foreign as Ring
66
68
67import Prelude hiding (length, sum, minimum, maximum)
69import Prelude hiding (length, sum, minimum, maximum)
68
70
69−
70-- $setup
71-- $setup
71-- >>> import Data.Bifunctor(bimap)
72-- >>> import Data.Bifunctor(bimap)
72-- >>> import qualified Streamly.Data.Fold as Fold
73-- >>> import qualified Streamly.Data.Fold as Fold
74+-- >>> import qualified Streamly.Internal.Data.Fold.Window as FoldW
75+-- >>> import qualified Streamly.Internal.Data.Ring.Foreign as Ring
76+-- >>> import qualified Streamly.Prelude as Stream
73-- >>> import Prelude hiding (length, sum, minimum, maximum)
77-- >>> import Prelude hiding (length, sum, minimum, maximum)
74
78
75-------------------------------------------------------------------------------
79-------------------------------------------------------------------------------
@@ -313,38 +317,35 @@ maximum n = fmap (fmap snd) $ range n
313mean :: forall m a. (Monad m, Fractional a) => Fold m (a, Maybe a) a
317mean :: forall m a. (Monad m, Fractional a) => Fold m (a, Maybe a) a
314mean = Fold.teeWith (/) sum length
318mean = Fold.teeWith (/) sum length
315
319
316−-- | Drop repeated elements within the specified
320+-------------------------------------------------------------------------------
317−-- tumbling window in the stream.
321+-- Distribution
318−-- /Pre-release/
322+-------------------------------------------------------------------------------
323+
324+-- XXX We can use a Windowed classifyWith operation, that will allow us to
325+-- express windowed frequency, mode, histograms etc idiomatically.
326+
327+-- | Count the frequency of elements in a sliding window.
319--
328--
320−-- >>> import qualified Streamly.Prelude as S
329+-- >>> input = Stream.fromList [1,1,3,4,4::Int]
321−-- >>> S.fold nub $ S.fromList [(1, Nothing), (1, Nothing), (3, Nothing), (4, Just 1)]
330+-- >>> f = Ring.slidingWindow 4 FoldW.frequency
331+-- >>> Stream.fold f input
322−-- fromList [(1,1),(3,1),(4,1)]
332+-- fromList [(1,1),(3,1),(4,2)]
323--
333--
334+-- /Pre-release/
335+--
324−{-# INLINE nub #-}
336+{-# INLINE frequency #-}
325−nub :: (Monad m, Ord a) => Fold m (a, Maybe a) (Map.Map a Int)
337+frequency :: (Monad m, Ord a) => Fold m (a, Maybe a) (Map.Map a Int)
326−nub = Fold step initial extract
338+frequency = Fold.foldl' step Map.empty
327
339
328 where
340 where
329
341
330− initial =
342+ decrement v =
331− return $ Partial Map.empty
332−
333− updateRefCounts new map0 = return $ Map.insertWith (+) new (1::Int) map0
334−
335− alter a m1 (Just v) =
336 if v == 1
343 if v == 1
337− then do
338− _ <- return $ Map.delete a m1
339− return Nothing
344+ then Nothing
340− else return $ Just (v -1)
345+ else Just (v - 1)
341− alter _ _ Nothing = error "Invalid old element"
346+
342−
343− step map0 (new, mOld) = do
347+ step refCountMap (new, mOld) =
344− m1 <- updateRefCounts new map0
348+ let m1 = Map.insertWith (+) new 1 refCountMap
345− Partial <$>
346− case mOld of
349+ in case mOld of
347− Just a -> Map.alterF (alter a m1) a m1
350+ Just k -> Map.update decrement k m1
348− Nothing -> return m1
351+ Nothing -> m1
349−
350− extract = return