14
$\begingroup$

I am running Mathematica 7. The following is admittedly a silly example, but suppose that I have a list list whose entries are either True or False. Suppose that I have some function truthFun[] which evaluates randomly to either True or False. I would like to call truthFun[] and print False until truthFun[] evaluates to True for the first time.

One way to do this is using a For loop. We can exit the loop "early" using Break[]. (As the documentation states, Break[] exits the nearest enclosing Do, For, or While loop.) For example, the following works:

truthFun[] := RandomChoice[{True, False}]

For[i = 1, i <= 10^8, i++,
   If[truthFun[] === False, Print[False], Break[]]];
Print["Finished"]

False

False

Finished

However, it is often recommended that Mathematica users avoid using loops (which are relatively slow in Mathematica, I think). Is it possible to accomplish the above using Table, which is probably faster?

I tried the following, but unfortunately it appears that Break[] does not work with Table:

truthFun[] := RandomChoice[{True, False}]

Table[If[truthFun[] === False, Print[False], Break[]], {i, 1, 10^8}];

False

False

False

Hold[Break[]]

Also, Mathematica gives me this error message:

Break::nofwd: No enclosing For, While, or Do found for Break[].

Is there an analogue to Break in Table? Thanks for your time.

$\endgroup$
4
  • 1
    $\begingroup$ This would work: Map[Print, First@Split@list] $\endgroup$
    – Jens
    Jan 26, 2013 at 17:33
  • 3
    $\begingroup$ If you want to keep the results accumulated by Table so far, have a look at my implementation of abortable table here. It can be easily modified to work with Break or any other custom form of interruption, rather than Abort[]. $\endgroup$ Jan 26, 2013 at 18:13
  • 2
    $\begingroup$ Could use Scan to go over the table, and Return or Throw to exit on condition. If the latter, enclose the Scan in a Catch. $\endgroup$ Jan 26, 2013 at 22:38
  • 1
    $\begingroup$ Andrew, thanks for the Accept. By the way, I did not state it explicitly in my answer but you can use Return[Null, Table] or the equivalent Return[,Table] to get behavior similar to Break without the syntax error highlighting. $\endgroup$
    – Mr.Wizard
    Jan 28, 2013 at 18:57

2 Answers 2

22
$\begingroup$

The lightly-documented second argument of Return works:

Table[
 If[i < 3, Print@i, Return["Exit", Table]],
 {i, 100}
]

1

2

"Exit"

Other examples of use: (1), (2)

Additional information:
What can I use as the second argument to Return in my own functions?


Break also accepts a second argument but at least on my system the syntax highlighting is ugly:

Table[
 If[i < 3, Print@i, Break[Null, Table]],
 {i, 100}
]

1

2


Somewhat more standard but IMHO less convenient is Throw and Catch:

Table[
 If[i < 3, Print@i, Throw["Exit", "tableBreak"]],
 {i, 100}
] ~Catch~ "tableBreak"
$\endgroup$
9
  • 1
    $\begingroup$ +1 since it answers the question, but I wouldn't do it that way. Except maybe in compiled functions - I wonder if that second arg works with Compile... $\endgroup$
    – Jens
    Jan 26, 2013 at 18:17
  • 2
    $\begingroup$ Actually, I wouldn't use it in compiled functions either. Then For and While seems fine. $\endgroup$
    – Jens
    Jan 26, 2013 at 18:22
  • 2
    $\begingroup$ @Jens Thanks. I cannot always write a-guide-to-a-better-way answers (though I try) and sometimes the direct answer is more interesting to me. $\endgroup$
    – Mr.Wizard
    Jan 26, 2013 at 18:22
  • 5
    $\begingroup$ @Jens Return is very dangerous in compiled functions. If you in-line a compiled function with Return into another compiled function, the first Return will exit both. I can find an example if you like... $\endgroup$
    – Ajasja
    Jan 26, 2013 at 19:01
  • 1
    $\begingroup$ What if you wanted to interrupt Table, let's say at step 2, but have it return what it would have had returned if it had stopped at 2? I mean, Table[If[i < 3, i, Return["Exit", Table]], {i, 100}] does not return the same as Table[i, {i, 2}]. What if I wanted Table[If[i<3, i, ......], {i, 100}] to return {1, 2}? $\endgroup$
    – anderstood
    Dec 18, 2017 at 18:37
3
$\begingroup$

Clarification: this answer refers to the first the first version of the question, before its entire premise was changed.

So what you're trying to do is take an existing list and then go through its elements until a stopping criterion is reached. But since you already have the list

list={False,False,False,True,False,False};

it's not necessary to construct another Table, just as it's not necessary to use For and Do. Instead, use a function that can select the desired elements of your list according to a criterion you specify. In your case a simple approach is to use Split because it creates lists of "runs" (i.e., contiguous stretches in your input), based on a criterion that specifies what makes the elements of a run equivalent.

Your simple example doesn't even need any test argument for the criterion:

First@Split@list

{False, False, False}

The run stops when the first element is reached that's just different from the others.

Then you want to Print the results (actually, I think the above list is what you'd usually be looking for). If that's required, then you can do it now, after having collected the elements above:

Map[Print, %] 

False

False

False

Edit

In response to the edited question, one could first identify the position of the first element that satisfies the truthFunction, and then extract the part of the list up to that position:

truthFunction[x_] := TrueQ[x]
Most[
 list[[1 ;; First@First[Position[list, _?truthFunction, 1, 1]]
   ]
  ]]

(* ==> {False, False, False} *)

Here I decided to use Position with the fourth argument that says to look for the first occurrence. Since Position requires a search pattern, the truthFunction has to be preceded by _? or PatternTest.

$\endgroup$
1
  • $\begingroup$ Thanks for your time. Sorry for being silly. I was trying to make a simple working example, but I failed to include a test function. I have revised my question to reflect this. I would like to evaluate truthFun[] as few times as possible. I am really sorry take up your time. $\endgroup$
    – Andrew
    Jan 26, 2013 at 17:47

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.