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

痴心易碎 提交于 2021-01-28 05:00:04

问题


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 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


来源:https://stackoverflow.com/questions/65437663/haskell-elegant-way-to-filter-reduce-sequences-of-duplicates-from-infinte-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!