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.
Answer
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:
Perhaps also of interest:
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}}
Comments
Post a Comment