Making nice code: choosing one of several procedures

Happy new year mathematica gurus of stack exchange!

As I see it one of the major obstacles in getting decent at programming mathematica is that, not only do you need to learn how certain commands work, but rather that you mainly need to understand how to write your syntax. This is a typical such situation, I was hoping that someone might shine some light on how to do it.

I run this piece of code:

For[i = 1, i <= samples, i++,
AppendTo[fList,
f1[randomSeeds[[1 + (n - 1) (i - 1)]][[1]],
randomSeeds[[1 + (n - 1) (i - 1)]][[2]], 0, 0, 0, 0, 0, 0]];
]

For[i = 1, i <= samples, i++,
AppendTo[fList,
f1[randomSeeds[[1 + (n - 1) (i - 1)]][[1]],
randomSeeds[[1 + (n - 1) (i - 1)]][[2]],
randomSeeds[[2 + (n - 1) (i - 1)]][[1]],
randomSeeds[[2 + (n - 1) (i - 1)]][[2]], 0, 0, 0, 0]];
]

For[i = 1, i <= samples, i++,
AppendTo[fList,
f1[randomSeeds[[1 + (n - 1) (i - 1)]][[1]],
randomSeeds[[1 + (n - 1) (i - 1)]][[2]],
randomSeeds[[2 + (n - 1) (i - 1)]][[1]],
randomSeeds[[2 + (n - 1) (i - 1)]][[2]],
randomSeeds[[3 + (n - 1) (i - 1)]][[1]],
randomSeeds[[3 + (n - 1) (i - 1)]][[2]], 0, 0]];
]

For[i = 1, i <= samples, i++,
AppendTo[fList,
f1[randomSeeds[[1 + (n - 1) (i - 1)]][[1]],
randomSeeds[[1 + (n - 1) (i - 1)]][[2]],
randomSeeds[[2 + (n - 1) (i - 1)]][[1]],
randomSeeds[[2 + (n - 1) (i - 1)]][[2]],
randomSeeds[[3 + (n - 1) (i - 1)]][[1]],
randomSeeds[[3 + (n - 1) (i - 1)]][[2]],
randomSeeds[[4 + (n - 1) (i - 1)]][[1]],
randomSeeds[[4 + (n - 1) (i - 1)]][[2]]]];
]


As you can see most of the stuff is identical in the for loops, it's just the number of zeroes that varies in the end. In fact, I only wish to run one of these for loops at the time. Just above these for loops I specify the number of dimensions I'm working in (n in the code), for n=2 I want to run the first loop, for n=3 I want to run the second etc. At the moment I comment an uncomment the undesired parts of the code, but that seems like a very ugly solution to me.

So my question is this: is there a simple way of reducing these for copies of code into one copy? It seems to me as though this is a quite ineffective way of doing things.

Edit: Small clarification: Ideally I want something like this: I give the program "2" as input and it chooses the first for loop above etc.

Cheers, David

-

To begin with you should try to avoid explicit For loops in most cases. See Alternatives to procedural loops and iterating over lists in Mathematica. You will often also benefit from a functional rather than mutable style. Consider for example this function which does not rely on any global variables:

loop[fn_, seeds_, n_, samples_, jmax_] :=
fn @@ PadRight[#, 8] & /@
Join @@@ Table[seeds[[j + (n - 1) (i - 1), k]], {i, samples}, {j, jmax}, {k, 2}]


An example of use:

SeedRandom[1];
randomSeeds = RandomInteger[{-50, 50}, {99, 2}];

loop[f1, randomSeeds, 5, 8, 3]

{f1[30, -36, -50, 17, -47, 15, 0, 0],  f1[47, 18, 24, -35, -26, -46, 0, 0],
f1[33, 20, -49, -20, -2, -25, 0, 0],  f1[19, 6, -3, -22, 18, -24, 0, 0],
f1[36, 26, -7, -17, -6, 36, 0, 0],    f1[-12, -21, 25, -20, -33, 4, 0, 0],
f1[-44, -7, -48, 29, -33, -16, 0, 0], f1[1, -9, -35, -32, -5, -44, 0, 0]}


This matches the output of your first For loop. For the second and third:

loop[f1, randomSeeds, 5, 8, 3]

loop[f1, randomSeeds, 5, 8, 4]


I intentionally put all data upon which loop depends as arguments to avoid relying on global values. If you do not want to pass these explicitly you might rely upon Options. For example:

ClearAll[loop]

Options[loop] = {Function -> f1, "Seeds" :> randomSeeds};

loop[n_, samples_, jmax_, OptionsPattern[]] :=
OptionValue[Function] @@ PadRight[#, 8] & /@
Join @@@ Table[OptionValue["Seeds"][[j + (n - 1) (i - 1), k]],
{i, samples}, {j, jmax}, {k, 2}]


This relies on the global value of randomSeeds but it is no longer hard-coded. Now the call is simpler:

loop[5, 6, 3]

{f1[30, -36, -50, 17, -47, 15, 0, 0], f1[47, 18, 24, -35, -26, -46, 0, 0],
f1[33, 20, -49, -20, -2, -25, 0, 0], f1[19, 6, -3, -22, 18, -24, 0, 0],
f1[36, 26, -7, -17, -6, 36, 0, 0],   f1[-12, -21, 25, -20, -33, 4, 0, 0]}


You change the Options at any time with SetOptions:

SetOptions[loop, Function -> foo];

loop[5, 3, 4]

{foo[30, -36, -50, 17, -47, 15, 50, -27],
foo[47, 18, 24, -35, -26, -46, 50, 40],
foo[33, 20, -49, -20, -2, -25, -6, 23]}

-
Thank you for your quick replies. The link posted by Mr.Wizard seems most intreaging, I shall read it through at once! I like the use of switch too, it reminds me of C, there is a similar command there. I'll look it up! Why can't you accept two answers? >.< –  storluffarn Jan 4 at 21:33
@storluffarn I am glad I could help. Please let me know if you have trouble reading my code; I am always happy to explain it, but I do not by default include break-downs in my answers. Regarding Accepting two answers see: meta.mathematica.stackexchange.com/q/920/121 –  Mr.Wizard Jan 4 at 21:46

I certainly agree with everything Mr. Wizard says in his answer. Taking the question at face value you can give each loop a symbol so that f[1] := For[... f[2] := For[ ... and then use Switch:

Switch[n,1,f[1],2,f[2]...]


Or as Kuba suggests:

f[n]


But that is only valid if you use f[1]...f[n]... as your symbols.

-
+1 for "at face value" -- there is always merit in answering the actual question, even when it is (IMHO) the "wrong" question. –  Mr.Wizard Jan 4 at 1:55
So if you define f[1], f[2]..., why not just f[n]? :) –  Kuba Jan 4 at 1:59
@Kuba Hm... good point. I was thinking of a single Switch block with all the loops inside, even though I'd never actually write that myself. –  Mr.Wizard Jan 4 at 2:01
@Kuba That's the best syntax in this scenario. I like Switch because in general two pieces of code that you might want to control in this way may not be similar and so it might be more semantic to give them very different names. In that scenario you have to use Switch. –  Pickett Jan 4 at 2:14
I agree, just wanted to point that out as it hit me first. –  Kuba Jan 4 at 2:15
show 1 more comment