Reputation: 1
I want a function takeUntill
with the signature takeUntill :: (Int -> Bool) -> [Int] -> [Int]
.I did came out with the implementation but I'm looking for a cleaner solution to this problem than my existing one if it exists.
My current solution is :
takeUntill :: (Int -> Bool) -> [Int] -> [Int]
takeUntill p a = snd $ maximum $ [(length x, x) | x <- groups p a]
groups :: (Int -> Bool) -> [Int] -> [[Int]]
groups _ [] = []
groups p a = ((takeWhile p a):(groups p (drop 1 $ dropWhile p a)))
Upvotes: 0
Views: 223
Reputation: 18249
I think the way you are doing this looks OK, but the groups
function is messy - particularly the way you drop exactly 1 from the elements that don't satisfy p at each step, which can result in your result having a lot of superfluous empty lists inside it. (These of course won't affect takeUntil
provided at least 1 element of a
satisfies p
, but they're still there.)
I would rewrite groups
as follows, using some useful library functions:
groups p a = filter (p . head) $ groupBy ((==) `on` p) a
I don't know if it's more efficient or not, but I certainly find it easier to read. To give some explanation, groupBy
(http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-List.html#v:groupBy) is from Data.List
, and splits a list into a list of sublists according to whether a function of 2 consecutive arguments is true or not. And on
(http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Function.html#v:on) is a handy little function from Data.Function
which feeds the result of another function to the inputs of a binary function. The result is that
groupBy ((==) `on` p) a
splits the list up into sections where p
is always True
or always False
. Then we filter that into just the parts that are True.
Upvotes: 2