I'm looking for a function of type
[[(a, b)]] -> [(a, [b])]
and Hoogle tells me there isn't one, so I've written this:
transpose :: (Eq a) => [[(a, b)]] -> [(a, [b])]
transpose alists = uncurry zip $ foldl combine ([], []) alists
where combine memo new = foldl tally memo new
tally ([], []) (k, v) = ([k], [[v]])
tally ((ksHead:ksRest), (vsHead:vsRest)) (k, v) =
if k == ksHead
then (ksHead:ksRest, (v:vsHead):vsRest)
else (ksHead:ks, vsHead:vs)
where (ks, vs) = tally (ksRest, vsRest) (k, v)
In order of importance:
- Is there actually a built-in for this that Hoogle doesn't know about?
- Is
transpose
the right name for this thing? - Is there a better (more readable and/or more performant) way of writing this?
EDIT
Since someone's interested in the flavor:
I'm writing a stack ranking app, and ballots from the user come in in the form of [(Candidate, Rank)]
. In order to compute the winner by, for example, Borda count, I need to tally the ranking of each Candidate
by combining those ballots. Comments on the more general problem are also welcome.