Reap
does not work that way: when you provide a list of tags for Reap
only these tags are "watched for" and collected. This allows for much better memory management than collecting for all tags and discarding at the end.
In essence it works something like this for declared tags 1
, 2
, 3
:
{one, two, three} = {{},{},{}};
sow[x_, 1] := (one = {one, x}; x)
sow[x_, 2] := (two = {two, x}; x)
sow[x_, 3] := (three = {three, x}; x)
sow[x_, _] := x
SeedRandom[1]
Do[sow[i, RandomInteger[10^6]], {i, 10^7}]
Flatten /@ {one, two, three}
MaxMemoryUsed[]
{{30003, 1238414, 1529333, 3074569, 3401105, 4162839, 4715096, 5855206, 5971795, 6984287},
{238730, 652982, 946353, 1821955, 2018277, 2065726, 4483637,
4591412, 4733380, 4920935, 5283043, 5816356, 8272260, 8409277},
{2793919, 2803799, 3784289, 5018439, 6380588, 8799862, 9301537}}
15034792
You can see that advance knowledge of the tags is needed to set this up. Compare to the memory requirements of this:
SeedRandom[1]
Cases[
{#[[All, 1]], #[[1, 2]]} & /@
Table[{i, RandomInteger[10^6]}, {i, 10^7}] ~GatherBy~ Last,
{_, 1 | 2 | 3},
{1}
]
MaxMemoryUsed[]
{{{30003, 1238414, 1529333, 3074569, 3401105, 4162839, 4715096,
5855206, 5971795, 6984287}, 1},
{{238730, 652982, 946353, 1821955, 2018277, 2065726, 4483637,
4591412, 4733380, 4920935, 5283043, 5816356, 8272260, 8409277}, 2},
{{2793919, 2803799, 3784289, 5018439, 6380588, 8799862, 9301537}, 3}}
605960144
If you wish to replace Append
with something more efficient, consider using linked lists as I did in the sow
example above, or the Internal`Bag
class of functions.
HoldFirst
attribute ofReap
. This attribute is necessary forReap
to be influence the evaluation of its first argument. $\endgroup$Reap
can work with filtering tags which are only known when the code insideReap
is running. In such formulation, it makes perfect sense, but alas the answer is no. But one can always filter after the fact, and with a similar run-time performance (but possibly at the expense of memory use). $\endgroup$