Here's an evaluation-leak free way: (i.e. it will work even if s[1]
etc. have values outside the Table
)
n = 3;
Replace[
Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n],
v_ :> {v, {-1, 1}},
1
] /.
Hold[s___] :> Hold@Table[(*remove Hold to evaluate*)
expr,
s
]
(* Hold[
Table[expr, {s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}]] *)
As noted in the comment above, you'd need to remove the Hold
to let the table evaluate. To see how this works, I show some of the individual steps of the above expression:
(* list of s "variables" *)
s /@ Hold @@ Range@n
(* Hold[s[1], s[2], s[3]] *)
(* combine with t "variables" *)
Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n]
(* Hold[s[1], s[2], s[3], t[1], t[2], t[3]] *)
(* insert the iterator specifications *)
Replace[
Join[s /@ Hold @@ Range@n, t /@ Hold @@ Range@n],
v_ :> {v, {-1, 1}},
1
]
(* Hold[{s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}] *)
If you don't care about evaluation leaks, this is enough:
n = 3;
Hold@Table[expr, ##] & @@ (
{#, {-1, 1}} & /@ Join[s /@ Range@n, t /@ Range@n]
)
(* Hold[
Table[expr, {s[1], {-1, 1}}, {s[2], {-1, 1}}, {s[3], {-1, 1}}, {t[
1], {-1, 1}}, {t[2], {-1, 1}}, {t[3], {-1, 1}}]] *)
Again, you'd need to remove the hold in your actual code.
You could also consider using Array
if you can change in what way the variables are used:
n = 3;
Array[f[##] &, ConstantArray[2, n], {-1, 1}]
(* {{{f[-1, -1, -1], f[-1, -1, 1]}, {f[-1, 1, -1],
f[-1, 1, 1]}}, {{f[1, -1, -1], f[1, -1, 1]}, {f[1, 1, -1],
f[1, 1, 1]}}} *)
Here, the function f
simply gets the values of the s[…]
and t[…]
in sequence.