0
$\begingroup$

I want to perform a Do command with n variables, where n is set elsewhere in my code. How do I do that?

For example, suppose s={0,1} and n=2, then I want a code that runs

Do[Print[{var1,var2}],{var1,s},{var2,s}]

and when I set n=3, then I want a code that runs

Do[Print[{var1,var2,var3}],{var1,s},{var2,s},{var3,s}].

(Print is used just as a simple example here.) I have tried

Do[Print[ToExpression[Table["i"<>ToString[i],{i, n}]]],ToExpression[Table["{i"<>ToString[i]<>",s}",{i, 1, n}]]]

but Mathematica complains due to the result of the second ToExpression containing extra pair of curly brackets (Table produces a list). I tried removing these brackets with Row (as suggested https://community.wolfram.com/groups/-/m/t/1219718) or Delete (as suggested here Is there a function in Mathematica which removes brackets wrapping an expression?), but could not get code to work due to my limited knowledge of Mathematica.

I know I can do Tuples but that produces a large output when s is large (i.e., requires a lot of memory).

I will appreciate any comments.

$\endgroup$
  • 1
    $\begingroup$ Can you explain in more detail what you are trying to achieve in the end? Here's an easy way to compute an arbitrary dimensional array where the elements are the sums of indices. Array[Total[{##}] &, {3, 4, 2}] Notice that it generalizes to $n$ dimensions without problem. Can you explain your use case in enough detail that it becomes apparent why such a solution would not be possible for you? $\endgroup$ – Szabolcs May 11 at 10:56
  • $\begingroup$ @Szabolcs: Apologies for the missing context. I am trying to generate all n dimensional vectors such that a) all elements are drawn from s, b) the elements sum to 1 and c) the elements are increasing. One way to do this is to generate all n tuples from s and then test each tuple for a)-c). However, this generates all tuples at ones and requires a lot of memory when s is large. $\endgroup$ – Jan May 11 at 11:04
  • $\begingroup$ Since the elements must be increasing, I would use Subsets, not Tuples. This will improve performance significantly because you just got rid of a lot of permutations. If there are still too many subsets, you can use Subsets's 3rd argument to only generate the nth one, thus being able to iterate through them without generating all of them first. $\endgroup$ – Szabolcs May 11 at 11:39
  • $\begingroup$ @Szabolcs: Thank you. Let me confirm that using Subsets works as suggested. Thank you. $\endgroup$ – Jan May 11 at 12:00
1
$\begingroup$

If you want to loop over what would be the result of Tuples[s, {n}] without generating all tuples at once, then you need to recall that tuple generation is isomorphic to generating $n$-digit base-$b$ numbers, where b == Length[s]:

n = 3; s = {0, 1};
b = Length[s];
Do[Print[s[[IntegerDigits[k, b, n] + 1]]], {k, 0, b^n - 1}]

Otherwise, there is the option of programatically generating the iterators:

Do[Print[Array[K, n]], ##] & @@ ({#, s} & /@ Array[K, n])

Here, I use K[n] as the loop variable for each level.

$\endgroup$
  • $\begingroup$ There are 3 suggested ways to do what I originally asked: Subsets, $n$-digit base-$b$ and Array. All three work as intended. The $n$-digit base-$b$ seems to be the fastest. $\endgroup$ – Jan May 11 at 12:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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