# Speeding up Do loop with lists inside

The question is simple. I'm trying to improve the (time) performance of a "Do" loop that looks like the following MWE

xlist = Range[0., 1., 0.1];
ylist = Range[0., 2., 0.2];

f[x_, y_, z_] := x + 3*y - z

results = {};

Do[
input = Tuples[{xlist, ylist, {step}}];
evalf = f @@ Transpose[input];
AppendTo[results, {step, Mean@evalf}]
, {step, Range[-1., 1., 0.1]}]


What is the most efficient way to speed up a thing like this?

• Not in a position where I can answer rn, but it strikes me that you could simply use Table instead of a Do and AppendTo here. Also an iterator of the form {step, -1, 1, 0.1} might be better, instead of computing the whole Range; not sure. Mar 17, 2021 at 5:07
• Also, I don’t think you need to compute Tuples each time, since the step is constant in a given, well, step! Maybe simply compute xylist = Transpose @ Tuples[{xlist, ylist}] outside the loop, then instead of Do use results = Table[{step, Mean[f[#1, #2, step]& @@ xylist]}, {step, -1, 1, 0.1}]. Does that work as expected? (Sorry, not at a computer rn...) Mar 17, 2021 at 5:15
• Of course, given that your function is linear, we could simply compute Mean[#1 + 3*#2 & @@ Transpose[Tuples[{xlist, ylist}], or analytically simply $\bar{x} + 3\bar{y} = 0.5 + 3$, and then results = Table[{step, 3.5 - step}, {step, -1, 1, 0.1}], I think, but assuming you want to use an arbitrary function in general... :P Mar 17, 2021 at 5:25
• With[{ran = Range[-1., 1., 0.1]}, Transpose[{ran, Mean[xlist] + 3 Mean[ylist] - ran}] ] Mar 17, 2021 at 6:32
• I should have mentioned maybe that the function I'm working with is not linear... Mar 17, 2021 at 18:33

In MMA you seldom use loops. And when you nevertheless use a loop to create a list, do not use AppendTo, this will reallocate the list every time you add an element. Instead use Sow and Reap. Here is a solution without loops:

xlist = Range[0., 1., 0.1];
ylist = Range[0., 2., 0.2];

Clear[f, f1]
f[x_, y_, z_] := x + 3*y - z
f1[z_] = {z, Mean[f[xlist, ylist, z]]}

results = f1 /@ Range[-1., 1., 0.1]

• The key point of using Tuples in my original code was to create a grid on which you could evaluate the function. Then I want to obtain the fraction of points on this grid where the function is greater OR smaller than certain limits. For this I used Mean[UnitStep[f[args]-valmax]] + Mean[UnitStep[valmin- f[args]]]. If I'm right, with your code the function only gets evaluated at the pairs of values in the lists with the same position, and that's not what I want. Is there a workaround for Tuples or the UnitStep usage in this case? Mar 17, 2021 at 18:30
• I have difficulties understanding what you want. I think you should open an new question and explain exactly what you want. with a small test example. Mar 17, 2021 at 19:58