6
$\begingroup$

Consider

Table[
 If[i == 3, i = i + 2;];
 i
 , {i, 1, 10}]

{1, 2, 5, 4, 5, 6, 7, 8, 9, 10}

The above output is not what I would expect (namely {1, 2, 5, 6, 7, 8, 9, 10}).

Is there a way to dynamically change an iterator variable inside Table while it executes? If so, what is the appropriate syntax?

$\endgroup$
5
  • $\begingroup$ Why not use a Do loop instead? $\endgroup$
    – Syed
    Jan 6, 2022 at 19:17
  • $\begingroup$ @Syed I imagine to generate a table using Do one would have to first define output={}; and then do AppendTo[output,i] on every iteration. But that would create a whole new table on every iteration, which is very inefficient. Besides, doing Do instead of Table and using Print[i] suffers from the same issue. $\endgroup$
    – Kagaratsch
    Jan 6, 2022 at 19:20
  • 3
    $\begingroup$ You can do it in Compile, sort of: mathematica.stackexchange.com/questions/255724/… $\endgroup$
    – Michael E2
    Jan 6, 2022 at 19:33
  • $\begingroup$ @MichaelE2 That's interesting! Keeping track of the total number of loops then would give a way to get the desired table. $\endgroup$
    – Kagaratsch
    Jan 6, 2022 at 19:38
  • $\begingroup$ What you syntactically desire and your expected output are two different things...can you, please, clarify if you are trying to “skip” over the iterators you define, or are you trying to redefine the value of the iterators? Put another way, will you have a list of length 10 or length 8, in this example? $\endgroup$ Jan 7, 2022 at 5:48

5 Answers 5

6
$\begingroup$

There aren't many functions that create indeterminate-length lists. NestWhileList comes to mind. Sow/Reap, Append, Join etc. can be used with other iterators to create a list of an arbitrary length. FoldWhileList[f, givenlist,...] does not create a list longer than givenlist.

Here's a way to rewrite Table in terms of NestWhileList that allows the iterator to have its value changed. (You can create an infinite loop this way, as the usual risk with while loops.)

withDynamicIterator // ClearAll;
withDynamicIterator // Attributes = {HoldAll};
withDynamicIterator[
  Table[expr_, {x_, a_ : 1, b_, c_ : 1}]
  ] :=
 Block[{x},
  x = a;
  NestWhileList[# &[expr, x += c] &, Nothing, x <= b &]
  ]

OP's example:

withDynamicIterator@Table[
  If[i == 3, i = i + 2;];
  i, {i, 1, 10}]

(*  {1, 2, 5, 6, 7, 8, 9, 10}  *)

An example in which the iterator is set back:

SeedRandom[2];
primedQ[pressure_] := pressure >= 1;
p = 0;
withDynamicIterator@Table[
  If[i == 3 && ! primedQ[p], i = i - 3];
  p += RandomReal[{0.01, 0.3}];
  i, {i, 1, 10}]

(*  {1, 2, 0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  *)
$\endgroup$
1
  • $\begingroup$ (+1)!!! The example with pressure is mind-numbingly awesome! I am excited to share this with some of my local mathematica friends who are still learning. It’s easy (for me) to forget that you can use += & the-like within things like Table. Absolutely great example & answer. $\endgroup$ Jan 9, 2022 at 12:50
9
$\begingroup$

Use the correct iterator for the job, in this case use While instead of Table:

In[19]:= Module[{i = 0, list = {}},
    While[++i <= 10,
        If[i == 3, i += 2];
        AppendTo[list, i]
    ];
    list
 ]

Out[19]= {1, 2, 5, 6, 7, 8, 9, 10}

If you don't like the performance penalty associated with AppendTo there are plenty of alternatives.

$\endgroup$
4
  • 3
    $\begingroup$ The only answer that actually gives the desired output and a downvote? :-P $\endgroup$
    – Jason B.
    Jan 6, 2022 at 22:57
  • $\begingroup$ Don't worry, I already gave you a vote. It's fair. $\endgroup$ Jan 6, 2022 at 23:13
  • 1
    $\begingroup$ Thanks! The downvote could be because I don't actually use Table and modify the iterator's value (because that isn't possible). $\endgroup$
    – Jason B.
    Jan 6, 2022 at 23:16
  • $\begingroup$ "...because I don't actually use Table..." — people are always posting workarounds without directly answering the OP's question. You'd think for an impossible request it would be the preferred sort of answer, or at least that such helpfulness wouldn't be discouraged. $\endgroup$
    – Michael E2
    Jan 8, 2022 at 19:52
5
$\begingroup$

Edit: I misunderstood the question, but the technique remains. Don't try to redefine the iterator symbol, just use it as is.

Table[If[3 < i < 5, Nothing, i], {i, 1, 10}]    
(* {1, 2, 3, 5, 6, 7, 8, 9, 10} *)

In general, you should not think of symbols as being equivalent to the "variables" of other programming languages. If you really want a symbol with a mutable definition, you should probably localize it with Module.

$\endgroup$
5
$\begingroup$

Try this:

Table[If[i == 3, j := i + 2, j := i];
 j, {i, 1, 10}]


(*  {1, 2, 5, 4, 5, 6, 7, 8, 9, 10}  *)

Have fun!

$\endgroup$
3
$\begingroup$

You could use a Condition:

Table[
i /.a_:>Nothing/;2<a<5
, {i, 1, 10}]

{1,2,5,6,7,8,9,10}

If somehow you need to define the iterators to skip prior to evaluation, or want to control this without rewriting the Table:

ClearAll[n];
n=3;
Table[
i /.a_:>Nothing/;n<=a<n+2
, {i, 1, 10}]

{1,2,5,6,7,8,9,10}

$\endgroup$

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.