Collecting lists using Reap/Sow

I have a list like {{a,x},{b,y},{c,x},{d,z},{e,y}} and would like to produce from it a list formed by collecting all top-level elements whose second components are the same into a single list. For the list above, the desired output would be { {{a,c},x}, {{b,e},y}, {d, z}}. Here x, y, and z could also be lists, if that matters. This seems like an application of Reap and Sow. But the on-line documentation of these functions is pretty poor, and the examples don’t add much. Shifrin’s book keeps referring to a discussion of Reap and Sow in Part II, but I can’t actually find a part II. Is there a resource somewhere that I can look at to understand the ins and outs of these functions, and see some real examples of how to use them?

The simple Reap[Map[Sow[#, #[[2]]] &, r]], where r is the list above, produces almost what I want, but instead of {{a,c},x} above, it produces {{a,x},{c,x}}.

(I’m sure that someone will post a solution to my programming problem; for that I would be grateful. But I really would like to understand these functions better.)

EDIT: The code Reap[Map[Sow[#[[1]], #[[2]]] &, r], _, {#2, #1} &] // Rest does the trick. Perhaps there’s a better way. In any case, my question about documentation still stands.

=================

2

 

Probably GatherBy is the way to go here. What in the docs is unclear/missing in your opinion? There are several answers using Reap/Sow around, a search may be useful.
– Yves Klett
Mar 16 ’14 at 13:38

  

 

@YvesKlett My major whine was that there seemed to be no way to see exactly what Sow was doing, but looking at more examples, I realized that providing an undefined function name as the third argument of Reap will show me exactly what my Sow produced. I’m much happier now. And GatherBy with a little postprocessing worked as well, so now I have two possible solutions.
– rogerl
Mar 16 ’14 at 14:02

=================

1 Answer
1

=================

This question may be deemed a duplicate, as the specific operation has been addressed before (actually quite a few times as I recall). Nevertheless I shall attempt to provide a useful answer regarding Sow and Reap. First, I there are many examples of the use of these functions on this site, and I encourage you to search for them, as they will provide a broader application than is practical in a single answer.

For your given example you could write:

data = {{a, x}, {b, y}, {c, x}, {d, z}, {e, y}};

Reap[Sow @@@ data, _, {#2, #} &][[2]]

{{{a, c}, x}, {{b, e}, y}, {{d}, z}}

This doesn’t quite match your desired output but it is a more consistent format.

However, you mention: “Here x, y, and z could also be lists, if that matters.” Yes, it does matter, because if the second argument of Sow is a list it is not treated as a single tag but a list of tags. Therefore you need to wrap the list itself in {} to have it treated as a single tag. First an example of the failure:

x = {1, 2, 3};

Reap[Sow @@@ data, _, {#2, #} &][[2]]

{{{a, c}, 1}, {{a, c}, 2}, {{a, c}, 3}, {{b, e}, y}, {{d}, z}}

And then the correction:

Reap[Sow[#, {#2}] & @@@ data, _, {#2, #} &][[2]]

{{{a, c}, {1, 2, 3}}, {{b, e}, y}, {{d}, z}}

A few posts you should read:

Can someone explain this code for joining two lists by the first element of each sublist?
Defining Tags in Reap

Perhaps also of interest:

combining and comparing lists
Gather list elements by index

Version 10 update: although specifically Reap and Sow were requested I think it is worth noting that this can be done with Associations as well, e.g.:

{#2, #} & @@@ Normal @ GroupBy[data, Last -> First]

{{{a, c}, x}, {{b, e}, y}, {{d}, z}}