9
$\begingroup$

Sometimes because of conditionals, you cannot guarantee that Sow will be called at least once.

Reap[Sow[1]][[2,1]] results in {1}, which is perfect if one was going to discard the end value anyway, because only the list of sown values has value.

Reap[Null][[2, 1]] raises exception

"Part::partw: Part 1 of {} does not exist."

I use this code

ClearAll[reapList]
reapList::usage="gracefully collect all Sow expressions into list";
SetAttributes[reapList,HoldAll]
reapList[r__]:=Flatten[Reap[r,{_}][[2]],2]
(* unit tests follow *)
reapList[Sow[15]]
   {15}
reapList[Sow[{}]]
   {{}}
reapList[Sow[{16,17}];Sow[18];Print["hello"];Sow[{19,20}];21]
    hello
   {{16,17},18,{19,20}}
reapList[Null]
   {}
reapList[Sow[Null]; Sow[{Null}]]
   {Null,{Null}}
reapList[For[i = 95, i <= 100, i++, If[PrimeQ[i*2 - 1], Sow[i]]]]
   {96, 97, 99, 100}
reapList[For[i = 101, i <= 105, i++, If[PrimeQ[i*2 - 1], Sow[i]]]]
   {}

but there might be a better way than use of pattern {_} and Flatten[ ... ,2] that is so much shorter not much value in creating helper function.

Also, not clear to me how to generalize the "reapList" helper function for use with tags.

$\endgroup$
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the faq! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$ – Michael E2 Dec 9 '14 at 0:28
  • $\begingroup$ wait, now I am not sure what Sow[Null] and Sow[{Null}] should do $\endgroup$ – Manuel --Moe-- G Dec 9 '14 at 1:16
  • $\begingroup$ for clarity, I should add a test with some code where the condition if Sow is called zero or at least once is best discovered at run time $\endgroup$ – Manuel --Moe-- G Dec 9 '14 at 1:24
  • $\begingroup$ @Kuba yes, you are right - Flatten[Reap[r][[2]], 1] works $\endgroup$ – Manuel --Moe-- G Dec 9 '14 at 17:28
  • $\begingroup$ This isn't a question about Reap or Sow, but about how to deal with functions that may not return output (or, may return output that the next function doesn't expect). The answer is surely "design your functions' input and output carefully." $\endgroup$ – djp Mar 5 '15 at 9:39
8
$\begingroup$

Edit: I accidentally used Identity when I meant Sequence, but on reflection I believe Join @@ is better.

My two standard methods are Apply: (reference Formatting text through pattern matching and Quick multiple selections from a list)

Join @@ Reap[Sow[1]][[2]]
Join @@ Reap[Null][[2]]
Join @@ Reap[Sow /@ {1, 2, {}}][[2]]
{1}

{}

{1, 2, {}}

And ReplaceAll: (reference How to remove redundant {} from a nested list of lists?)

Reap[Sow[1]][[2]]             /. {x_List} :> x
Reap[Null][[2]]               /. {x_List} :> x
Reap[Sow /@ {1, 2, {}}][[2]]  /. {x_List} :> x
{1}

{}

{1, 2, {}}
$\endgroup$
  • 1
    $\begingroup$ Identity@@@ fails with more than one item sown Identity @@@ Reap[Sow[1]; Sow[2]][[2]] $\endgroup$ – Manuel --Moe-- G Dec 9 '14 at 19:53
  • $\begingroup$ @Manuel Thank you! I meant to use Sequence, not Identity. $\endgroup$ – Mr.Wizard Dec 9 '14 at 23:47
  • $\begingroup$ @Manuel Come to think of it Join would be better I believe. $\endgroup$ – Mr.Wizard Dec 9 '14 at 23:53
  • $\begingroup$ @Manuel Thanks for the Accept. $\endgroup$ – Mr.Wizard Dec 9 '14 at 23:59
4
$\begingroup$

In Mathematica v10.1 there's undocumented GeneralUtilities`ReapList function. It accepts two arguments: expression and a tag.

Using it on adapted test suite from OP:

Needs["GeneralUtilities`"]
ClearAll[tag]
ReapList[Sow[15, tag], tag]
(* {15} *)
ReapList[Sow[{}, tag], tag]
(* {{}} *)
ReapList[
    Sow[{16, 17}, tag]; Sow[18, tag]; Print["hello"]; Sow[{19, 20}, tag]; 21,
    tag
]
(* hello *)
(* {{16, 17}, 18, {19, 20}} *)
ReapList[Null, tag]
(* {} *)
ReapList[Sow[Null, tag]; Sow[{Null}, tag], tag]
(* {Null, {Null}} *)
ReapList[For[i = 95, i <= 100, i++, If[PrimeQ[i*2 - 1], Sow[i, tag]]], tag]
(* {96, 97, 99, 100} *)
ReapList[For[i = 101, i <= 105, i++, If[PrimeQ[i*2 - 1], Sow[i, tag]]], tag]
(* {} *)
$\endgroup$
2
$\begingroup$

@Kuba is correct

Flatten[Reap[r][[2]], 1]

is a good substitute for Reap[r][[2,1]] when cannot guarantee at least one Sow

the line above should be substituted with

reapList[r_] := Flatten[Reap[r][[2]], 1]

because the __ is unnecessary as well

$\endgroup$
1
$\begingroup$

Perhaps cleaner to construct your expression in a way that guarantees at least one Sow[] call.

  Table[Rest@First@Last@Reap[Sow[Null]; If[i != 2, Sow[i]]], {i, 3}]

{{1}, {}, {3}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.