Reputation: 83
I imagined the following code:
compress :: [[a]] -> [(Int,a)]
compress [[]] = []
compress [(x:xs)] = (1 + length (takeWhile x xs), x) : compress [(dropWhile x xs)]
I want to count each element in a list of lists. There are identical elements in each list, for example:
[[1,1,1], [2,2]]
.
I can only achieve the following output:
[(1,[1,1,1]), (1,[2,2])]
, but what I really need is this:
[(3,1), (2,2)]
.
I can't get deep enough to count the element in each list and probably made it more complicated with takeWhile dropWhile, hence each list has the same element in it.
Upvotes: 0
Views: 696
Reputation: 531075
What you want is to
length
and head
to the remaining listsControl.Arrow
provides a useful operator &&&
which, when specialized to functions, looks like
f &&& g = \x -> (f x, g x)
With that, you can simply write
compress = map (length &&& head) . filter (not . null)
Using a list comprehension, it's just
compress xs = [(length x, y) | x@(y:_) <- xs]
The pattern match implicitly filters out the empty lists while extracting the first element without a call to head
.
Upvotes: 3
Reputation: 26161
This seems to be a better fit for a folding job since conditionally you will drop some of the sublists (ie when length
is 0). One approach could be
Prelude> let comp = foldr (\s r -> if null s then r else (length s, head s):r) []
Prelude> comp [[1,1,1],[2,2,2],[],[5,5,5,5,5,5]]
[(3,1),(3,2),(6,5)]
Upvotes: 2