5
$\begingroup$

I am trying to code a while loop that uses AppendTo to append the loop variable to an empty list.

even = {}
i = 1; While[i <= 5, Print[i]; AppendTo[even, i]; i++]

This code does not give any output. Can someone please tell what I am doing wrong? Thanks!

$\endgroup$

closed as off-topic by Szabolcs, garej, m_goldberg, MarcoB, Öskå Jul 28 at 11:33

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question arises due to a simple mistake such as a trivial syntax error, incorrect capitalization, spelling mistake, or other typographical error and is unlikely to help any future visitors, or else it is easily found in the documentation." – Szabolcs, garej, m_goldberg, MarcoB, Öskå
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 3
    $\begingroup$ The code is not intended to give an output. It alters the symbol even five times, then even contains the (desired?) output - all numbers, not only the even ones. $\endgroup$ – mgamer Jul 22 at 15:40
  • 7
    $\begingroup$ It should be noted that the AppendTo function isn't ideal for loops. The documentation explains in more detail. $\endgroup$ – Aaron Stevens Jul 23 at 14:53
  • 3
    $\begingroup$ Can you explain why you expect this piece of code to return a value (an output) at all? While does not return anything. If it did, what would be a reasonable thing for it to return? $\endgroup$ – Szabolcs Jul 24 at 8:44
5
$\begingroup$

Try

even = {} ; 
i = 1; 
While[i <= 5, Print[i];If[EvenQ[i], AppendTo[even, i]]; i++]

even
(*{2, 4}*)
$\endgroup$
4
$\begingroup$

The standard Table function also supports multi-line inputs, the last line will be used to create the table

Table[Print[i]; i, {i, 5}]

The output would look like this:

even = Table[Print[i]; i, {i, 5}]

1
2
3
4
5
{1, 2, 3, 4, 5}

But the value stored for even is just:

{1, 2, 3, 4, 5}
$\endgroup$
4
$\begingroup$

Linked lists (see Performance tuning in Mathematica?) are another, efficient alternative.

even = {}
i = 1; While[i <= 5, even = {even, i}; i++]

Flatten[even]

(*  { 1, 2, 3, 4, 5 }  *)

(I don't know why people use Print[] except for debugging. I suppose it's a C thing. To monitor progress, you can use Monitor[] or my current favorite, PrintTemporary@Dynamic@{Clock[Infinity], i}. To output data, there are better ways than Print[].)

$\endgroup$
4
$\begingroup$

Sow/Reap is more appropriate than AppendTo in the context of step-by-step list building: the latter takes longer as your list gets longer, whereas the former keeps up its speed until the end.

i = 1;
even = Reap[While[i <= 5, Print[i]; Sow[i]; i++]][[2, 1]]
(*    1    *)
(*    2    *)
(*    3    *)
(*    4    *)
(*    5    *)
(*    {1, 2, 3, 4, 5}    *)

Of course, this is only useful if you do something more complex in the loop. For this particular case, Table is even better, as user2757771 points out.

$\endgroup$
3
$\begingroup$

Just to go overkill on Michael E2's point that Print is pretty much useless except in a debug environment, here's a little automated Monitor:

monitored~SetAttributes~HoldAll;
monitored[
  monitoredVars : {__Symbol} | Automatic : Automatic,
  expr_,
  ignoredContexts : StringPattern`StringPatternQ : "System`"
  ] :=
 Replace[
  If[Hold[monitoredVars] === Hold[Automatic],
   Thread[
    DeleteDuplicates@
     Cases[Hold[expr], 
      s_Symbol?(Function[Null, ! StringMatchQ[Context[#], ignoredContexts], 
          HoldFirst]) :>
       Hold[s],
      Infinity
      ],
    Hold
    ],
   Hold[monitoredVars]
   ],
  Hold[mvars_] :>
   (
    PrintTemporary@
     Internal`LoadingPanel@Dynamic[
      Grid[
       {
        {"Time:", NumberForm[Quantity[Clock[Infinity], "Seconds"], 3]},
        {"Vars:", 
         Grid[
          {Row@{Extract[#, 1, Defer], ":"}, ReleaseHold[#]} & /@ 
           Thread[Hold[mvars]],
          Alignment -> {Left, Top}
          ]
         }
        },
       Alignment -> Left
       ]
      ];
    expr
    )
  ]

Then we can watch what happens (the Pause is just there to be able to see it happen):

monitored[
 even = {};
 n = 50;
 i = 1; While[i <= n, Pause[.1]; even = {even, i}; i++];
 Flatten[even]
 ]

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, \
41, 42, 43, 44, 45, 46, 47, 48, 49, 50}

enter image description here

We can also just watch i:

monitored[
 {i},
 even = {};
 n = 25;
 i = 1; While[i <= n, Pause[.1]; even = {even, i}; i++];
 Flatten[even]
 ]

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
22, 23, 24, 25}
$\endgroup$
0
$\begingroup$

If you wanted to Print the list at the end of the While loop, you can do the following

Module[{even = List[], i},
 i = 1;
 While[i <= 5, 
  Print["Now appending " <> ToString[i] <> " to the list"]; 
  AppendTo[even, i]; i++];
 even
 ]
$\endgroup$
0
$\begingroup$

Just for fun, going full functional, and making use of the magic Nothing symbol:

feven[n_?EvenQ] := n
feven[_] = Nothing;
Map[feven, Range[5]]
(* {2, 4} *)

If you must see the input, you can look at what Range[5] yields.

This kind of approach helps speed things up if the function you're mapping to the input is complicated and expensive. In that case, use ParallelMap. Factoring the problem into simple functions you can try out before composing higher level (but still simple) expressions from them also avoids much difficult debugging.

$\endgroup$

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