How do Reap and Sow work in this context

I have a list of points in 3D and I need to count how many times each point is repeated. For a similar problem with a list of characters many different solutions have been proposed in this post: solutions. Among those, I have here select this solution which is faster:

stringTally = Last @ Reap[Sow[1, #], _, {#, Tr@#2} &] &;
(* to be used as in this example to catch 4 repetitions *)
(* Cases[ stringTally @ list, {x_, 4}:>x] *)


Unfortunately I cannot understand how Reap works in stringTally. I tried to decompose it but the use of two pure functions make the expression a little bit complicated.

• blog.wolfram.com/2011/04/20/… Sep 30 '15 at 18:09
• @PatrickStevens, I know how does it work and I have already read this blog. Sep 30 '15 at 18:18
• If you use Trace on your list of character example (e.g. Cases[stringTally@list, {x_, 4} :> x] and at the same time carefully read the documentation on a separate window you should see how it works.
– gwr
Sep 30 '15 at 18:40
• You might, I believe, also write stringTally a bit differently: stringTally = Last@Reap[Sow[1, ##], _, {#1, Tr@#2} &] &. So the ## will take the list as it is (with each element being a tag for Sow and the #1,#2 in the pure function at the end work on each collection as part or the Reap. Tr@#2 will simply give the total for a vector and each collection will have a number of 1s for each instance as its second part. Hope that helps -- sometimes Mma is very compact and fast but not quite readable for humans...
– gwr
Sep 30 '15 at 18:47
• @gwr, there is only one argument (to stringTally) so # vs ## makes no difference. Sep 30 '15 at 19:20

We can see from this expression

Reap[Sow[1, #] & /@ {1, 1, 2, 3}, _, f]
(* Out: {{1, 1, 1, 1}, {f[1, {1, 1}], f[2, {1}], f[3, {1}]}} *)


how Sow and Reap interact in general. In this example f is {#, Tr@#2} &. Tr in this context works just like Total but it can be faster. But the sum of the second part is just the sum of 1s, the number of times that the particular tag has been sown (because 1 is sown each time).

• The only thing I'd mention is that Reap is of the form Reap[expr, pattern, function] and here the pattern is _ which will match anything. Sow then organizes by tag and Reap applies the final function.
– kale
Sep 30 '15 at 18:25

The answer in the link you supplied indicates that the use of the Sow and Reap approach performs better than Tally when strings are involved.

However, to count the number of occurrences in your list of 3D points, Tally is actually better.

list = Partition[RandomInteger[15000, 300000], 3];

Tally@list // Timing // First


0.078 seconds on my machine while

Last@Reap[Sow[1, list], _, {#, Tr@#2} &] // Timing // First


takes 1.59 seconds.