# Append in For loop does not work

I need to break my for loop in case of an thrown message and append s to the result list. Breaking the loop works, but my result is empty. I can not use Table[] because it does not support Break[].

EDIT: s has the form of list, so I get a Table structure for result

EDIT 2: AppendTo[] yields empty result too.

result = {};
For[i = 0, i < 6, i++,
s = {Quiet[
Check[If[i == 3, Message[FindRoot::jsing, x, 1], i], "Nan",
FindRoot::jsing]]};
If[s == "Nan", Break[], AppendTo[result, s]];
]
result


yields:

{}


Any help appreciated.

-

result = {};
For[i = 0, i < 6, i++,
s = Check[If[i == 3, Message[FindRoot::jsing, x, 1], i], "Nan",
FindRoot::jsing];
Print[s];
If[s == "Nan", Break[], result = {result, s}];]
Flatten[result]


or

result = {};
For[i = 0, i < 6, i++,
s = Check[If[i == 3, Message[FindRoot::jsing, x, 1], i], "Nan",
FindRoot::jsing];
Print[s];
If[s == "Nan", Break[], AppendTo[result, {s, dim}]];]
result

-
this works for one dimensional form of s but not for lists (edited problem, sorry) –  Martin Scherer Apr 19 '12 at 17:30
second one has table structure, thank you. –  Martin Scherer Apr 19 '12 at 17:42

The reason Append[] isn't working in your loop is that it returns a new list with your new element added to the end.

If you want to change the list in place, you should use AppendTo[] instead.

-
thx, now I know why Append in loops is evil! –  Martin Scherer Apr 19 '12 at 17:34
@MartinScherer Oh no, the main reason for that (Append being evil in loops) is not it. It is that the full list is copied to append a single element. –  Leonid Shifrin Apr 19 '12 at 17:35
calling copy constructors all the time :) –  Martin Scherer Apr 19 '12 at 17:40
@LeonidShifrin, which suggests an interesting follow-up question. Is AppendTo's implementation equally eager to copy things repeatedly? I can imagine an implementation where the Append version is forced to copy with every operation, but where AppendTo is implemented much like C++'s std::vector and only has to copy some of the time instead of on every step. I just ran some Timings and it looks like their behavior is almost identical. –  sblom Apr 19 '12 at 17:48
@sblom I noticed that I did not really answer your question. The answer is yes, AppendTo is just as bad in this regard as Append. Moreover, you can see that AppendTo has been actually implemented with Set and Append, by using On[Set], and then say a = Range[5]; AppendTo[a, 6]. –  Leonid Shifrin Apr 19 '12 at 19:31

You may not be able to use Table with Break[] but you can use Do:

Break[]
exits the nearest enclosing Do, For or While.

I also prefer Sow and Reap for speed and flexibility.

Reap[
Do[
s = Check[If[i == 3, Message[FindRoot::jsing, x, 1], i], "Nan", FindRoot::jsing];
If[s == "Nan", Break[], Sow@s],
{i, 0, 5}
]
][[2, 1]]

{0, 1, 2}

-

In an effort to "say no to loops", here is an alternative that substitutes For and Break with Fold and a Throw/Catch construct. There might be another alternative using FoldList and fewer uses of Flatten, but it's late at night here and I wasn't able to get that quite working. This works:

Catch@Fold[
With[{chk =
Check[If[#2 == 3, Message[FindRoot::jsing, x, 1], #2], "Nan",
FindRoot::jsing]},
If[chk == "Nan", Throw[Flatten@{#1, #2}],
Flatten@{#1, chk}]] &, {}, Range[6] ]


FindRoot::jsing: Encountered a singular Jacobian at the point x = 1. Try perturbing the initial point(s). >>

{1, 2, 3}

I think approaches such as this are preferable to For loops, since the latter tends to result in iterator variables (in this case, i) that remain globally defined, which is probably not what you want.

-