Reputation: 107
I'm trying to take init part of list while elements differs from previous only by one. A simple task could be implemented like:
takeAsc:: (Eq a, Enum a) => [a] -> [a]
takeAsc [] = []
takeAsc [x] = [x]
takeAsc (x:y:xs)
|y == succ x = x: takeAsc(y:xs)
|otherwise = [x]
But that's just hurt my feelings. I believe, that's pretty wide used pattern, and I'm just missing some specific function. I've tried to use groupBy or takeWhile, but it looks like they do not do what I want. Could anybody point more elegant solution for that?
Upvotes: 2
Views: 317
Reputation: 53881
A simple way to do this would be
takeAsc :: (Enum a, Eq a) => [a] -> [a]
takeAsc [] = []
takeAsc (x:xs) = (x:) . map fst . takeWhile pred . zip xs $ x:xs
where pred (a, b) = a == succ b
Or in English,
succ
of b
is a
It avoids somewhat icky explicit recursion and GHC should be clever enough to optimize this pretty well.
Upvotes: 2
Reputation: 54058
You could implement it as
takeAsc [] = []
takeAsc xss@(x:xs) = (x:) $ map fst $ takeWhile (uncurry (==)) $ zip xs $ map succ xss
You still have to include both cases, though.
> takeAsc [1, 2, 3, 4]
[1, 2, 3, 4]
> takeAsc [1, 3, 4, 5]
[1]
If you don't like that it always returns at least 1 element for a non-empty list, you would have to use a more verbose solution like you have above, but if you're going for a one-liner this is the best I can come up with.
Upvotes: 3