@David: The standard x_ is actually short for x:_, but the former is so common that many people don't recognize the latter. Both are read "the pattern named x that matches Blank[]".
–
SimonAug 7 '11 at 22:29

I did not see you solution until my last edit. I was thinking along the same lines, but the main problem that took me some time to figure out was to handle arbitrary number of terms in the sublists in the rule-based approach - yours only handles exactly two terms.
–
Leonid ShifrinAug 7 '11 at 19:17

@Leonid You are right, but I am not sure if such generalization is asked for in the question
–
belisariusAug 7 '11 at 19:22

If the "foo" and "bar" sublists are guaranteed to be aligned with one another (as they are in the example) and if you will consider using functions other than Gather/Collect/Transpose, then MapThread will suffice:

This method is quite generic. I used to use functions such as GatherBy before for treating huge lists I generate in Monte-Carlo simulations. Now with SelectEquivalents implementations for such operations are much more intuitive. Plus it is based on the combination Reap and Sow which is very fast in Mathematica.