Evg
Evg

Reputation: 3080

haskell elegant way to filter (reduce) sequences of duplicates from infinte list of numbers

This is a function that produces an infinite list of random numbers

import System.Random
values :: [Int]
values = map fst $ scanl (\(r, gen) _ -> randomR (1,10) gen) (randomR (1,10) (mkStdGen 1)) $ repeat ()

I want to reduce sequences for duplicate elements into one element e.g [2,3,4,1,7,7,7,3,4,1,1,1,3,..] -> [2,3,4,1,7,3,4,1,3,..]

So, I need some elegant function "f" from [Int] -> [Int] that do this. Also, it must work with an infinite list lazily, so if I run

f values

it must not hang and output data in real-time

Upvotes: 2

Views: 139

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476729

You can work with group :: Eq a => [a] -> [[a]] to make a list of groups. So for the given sample data, this will generate:

Prelude> import Data.List(group)
Prelude Data.List> group [2,3,4,1,7,7,7,3,4,1,1,1,3]
[[2],[3],[4],[1],[7,7,7],[3],[4],[1,1,1],[3]]

Then we can for each sublist only yield the first element with head, we know that such element exists, since otherwise it would never have constructed a new group in the first place:

Prelude Data.List> map head (group [2,3,4,1,7,7,7,3,4,1,1,1,3])
[2,3,4,1,7,3,4,1,3]

This thus means that you can define f as:

import Data.List(group)

f :: Eq a => [a] -> [a]
f = map head . group

This works on infinite lists as well. For example if we end the list with an infinite list of 5s, then it processes the list until that five and keeps looking for a new value:

Prelude Data.List> map head (group (2 : 3 : 4 : 1 : 7 : 7 : 7 : 3 : 4 : 1 : 1 : 1 : 3 : repeat 5))
[2,3,4,1,7,3,4,1,3,5

or we can make use of the group :: (Foldable f, Eq a) => f a -> [NonEmpty a] of Data.List.NonEmpty:

import Data.List.NonEmpty(group)
import qualified Data.List.NonEmpty as NE

f :: Eq a => [a] -> [a]
f = map NE.head . group

Upvotes: 2

Related Questions