问题
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
回答1:
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 5
s, 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
来源:https://stackoverflow.com/questions/65437663/haskell-elegant-way-to-filter-reduce-sequences-of-duplicates-from-infinte-list