3
$\begingroup$

This feature has long troubled me, I would like to share it.
If Reap has non-empty set of sown, result looks like:

res = Reap[Sow[a]; b; Sow[c]; Sow[d]; e]
{e, {{a, c, d}}}

If there was no any Sow we have:

res = Reap[e]
{e, {}}

I'd like to assign resulting list of sown values to a new variable,
even it is empty.
Natural way

newList = res[[2,1]]

not work in second case, we have error:

Part 1 of {} does not exist

so we need some conditional:

newList = If[res[[2]]!={},res[[2,1]],{}]

Is there a way to make it smarter?

UPD
Thanks to all for cool answers, so I'm confused to choose single one

$\endgroup$
0

7 Answers 7

7
$\begingroup$

Using the second argument of First:

First[Reap[a][[2]],{}]
(* {} *)
$\endgroup$
1
  • $\begingroup$ This only works in versions later than 10.2 $\endgroup$
    – Somos
    Commented May 26 at 3:38
4
$\begingroup$

If you just want to make a list of sown values, how about using Flatten?

res = Reap[Sow[a]; b; Sow[c]; Sow[d]; e];
Flatten[Last[res]]
(* {a, c, d} *)

res = Reap[e];
Flatten[Last[res]]
(* {} *)
$\endgroup$
2
  • $\begingroup$ It's worked code-golf style which I like, thanks! $\endgroup$
    – lesobrod
    Commented May 25 at 14:35
  • 2
    $\begingroup$ But! There is a pitfall. I need to sow 2D points, so single Flatten works not correct, we should use Flatten[...,1] $\endgroup$
    – lesobrod
    Commented May 25 at 16:44
4
$\begingroup$
Reap[Sow[a]; b; Sow[c]; Sow[d]; e, {_}, Splice[#2] &][[2, 1]]

(* {a, c, d} *)
Reap[e, {_}, Splice[#2] &][[2, 1]]

(* {} *)

Original Answer

Reap[Sow[a]; b; Sow[c]; Sow[d]; e, {_}, Delete[#2, 0] &][[2, 1]]

(* {a, c, d} *)

Reap[e, {_}, Delete[#2, 0] &][[2, 1]]
   
(* {} *)
$\endgroup$
1
  • 1
    $\begingroup$ This approach should be useful in some conditions, thank you! $\endgroup$
    – lesobrod
    Commented May 25 at 14:38
4
$\begingroup$

Rather than make assumptions about structure, I'd recommend building in your updating process to the Reap explicitly. Here are a couple of ways:

1. Use tags and a function to clearly organize the results:

{res, reaped} = Reap[Sow[a, "newList"]; b; Sow[c, "otherList"]; Sow[d, "newList"]; e, _, Rule]
(* {e, {"newList" -> {a, d}, "otherList" -> {c}}} *)

Now you can extract whatever you need with some simple pattern matching or whatever.

FilterRules[reaped, "newList"]
(* {"newList" -> {a, d}} *)

"newList" /. reaped
(* {a, d} *)

Query["newList"][reaped]
(* {a, d} *)

This approach gives you more semantic clarity in the case when nothing is reaped.

{res, reaped} = Reap[e, _, Rule]
(* {e, {}} *)

FilterRules[reaped, "newList"]
(* {} *)

"newList" /. reaped
(* "newList" *)

Query["newList"][reaped]
(* Missing["PartInvalid", "newList"] *)

If Rule doesn't fit your situation, you can obviously come up with whatever other representation that you want.

2. Perform the assignment as a side-effect:

newList = {};
Reap[Sow[a]; b; Sow[c]; Sow[d]; e, _, (newList = #2) &]
(* {e, {{a, c, d}}} *)

newList
(* {a, c, d} *)

newList = {};
Reap[e, _, (newList = #2) &]
(* {e, {}} *)

newList
(* {} *)
$\endgroup$
3
$\begingroup$

How about defining a helper function?:

Clear[fix];
fix[{a_, {b_List}}] := {a, b}
fix[expr_] := expr

Usage:

{res1, reaped1} = fix@Reap[e];
res1
(* e *)

reaped1
(* {} *)

{res2, reaped2} = fix@Reap[Sow[a]; b; Sow[c]; Sow[d]; e];
res2
(* e *)

reaped2
(* {a, c, d} *)
$\endgroup$
1
  • $\begingroup$ @xzcd, This is good example of right functional code style, thank you! $\endgroup$
    – lesobrod
    Commented May 25 at 14:33
3
$\begingroup$

A data-set-like approach:

res = Reap[Sow[a, "X"]; b; Sow[c, "X"]; Sow[d, "X"]; e, _, Rule];
newX = Lookup[Last@res, "X", {}]
(* {a, c, d} *)

res = Reap[a; b; c; d; e, _, Rule];
newX = Lookup[Last@res, "X", {}]
(* {} *)

Oh. I just noticed @leric's is half-similar. Anyway, I remember reading on this site a recommendation to always use tags with Sow/Reap (and Throw/Catch, too).

$\endgroup$
3
$\begingroup$

Sow the magic disappearing list element Nothing as the first thing in the Reap block:

Reap[Sow[Nothing]; e]
(* {e, {{}}} *)
$\endgroup$
1
  • $\begingroup$ Finally it may be simplest solution without any additional assumptions! $\endgroup$
    – lesobrod
    Commented May 28 at 4:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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