What about this?
import Data.List
import Data.Function
data P = P1 | P2 | P3 deriving Show
x = [(8, P1), (8, P2), (10, P3)]
fun list = let lists = groupBy ((==) `on` fst) x -- [[(8,P1),(8,P2)],[(10,P3)]]
nums = map (fst . head) lists -- [8,10]
ps = (map . map) snd lists -- [[P1,P2],[P3]]
in zip nums ps -- [(8,[P1,P2]),(10,[P3])]
In lists
I've grouped the items by equality on the number, in nums
I've extracted the number which is common to all items in each group, in ps
I've extracted those P*
things, whatever they are, via (map . map) . snd
which applies snd
through two functorial layers.
Note that if in general the items in x
with equal number are not necessarily adjacent (in your example they are), you might want to sort
the list before using groupBy
, using an appropriate sorting algorithm, as suggested in the comments below.
As regards your desired output
[(8, [P1, P2]), (10, P3)]
this is simply not possible to obtain, because in Haskell all the elemnts of a list have the same type, but (8, [P1, P2])
and (10, P3)
have to different types, namely (Time, [Person])
and (Time, Person)
. This was already implied by some of the comments under your question, but you haven't corrected your question yet (you should). In my answer I've assumed you meant to write [(8, [P1, P2]), (10, [P3])]
.
As regards your attempt
groupTogether :: [(Time, Person)] -> [(Time, Person)]
groupTogether [] = []
groupTogether ((x, y) : (a, b) : ks)
| x == a = (x, (y : (b))) : groupTogether ks
| otherwise = (x, y) : groupTogether ((a, b) : ks)
there are several syntactic problems with it:
- the signature is wrong, as it signals that the output has the same type of the input; this is certainly possible, but does not reflect the (corrected) desired output; probably you meant to write
groupTogether :: [(Time, Person)] -> [(Time, [Person])]
groupTogether [] = []
handles an empty list input, whereas groupTogether ((x, y) : (a, b) : ks)
handles a two-elements-or-more list input, but there's no way to deal with a singleton list, which is exactly what the "exaustive pattern missing" error alludes to;
- since
y
and b
have the same type, Person
, the expression y : (b)
is incorrect because it's equivalent to y:b
, and :
wants an a
on the left and a [a]
on the right; you might want to change that to y:[b]
, or maybe [y,b]
;
- in a similar way,
y
in the otherwise
case should be [y]
.
However, even if you apply the corrections above, there would still be something that is not quite right. Look at this:
groupTogether ((x, y) : (a, b) : ks)
| x == a = (x, y : [b]) : groupTogether ks
You're pattern matching the first two pair in the list and putting them in one single pair, but what if the first pair in ks
has another a
as its first element? You're leaving it in ks
, not grouping it with the other two. This is either wrong or not clear from the text of your question, in which case you should improve it.