I'd like something like this:
each[i_, {1,2,3},
Print[i]
]
Or, more generally, to destructure arbitrary stuff in the list you're looping over, like:
each[{i_, j_}, {{1,10}, {2,20}, {3,30}},
Print[i*j]
]
Usually you want to use Map
or other purely functional constructs and eschew a non-functional programming style where you use side effects. But here's an example where I think a for-each construct is supremely useful:
Say I have a list of options (rules) that pair symbols with expressions, like
attrVals = {a -> 7, b -> 8, c -> 9}
Now I want to make a hash table where I do the obvious mapping of those symbols to those numbers. I don't think there's a cleaner way to do that than
each[a_ -> v_, attrVals, h[a] = v]
In this example, we transform a list of variables:
a = 1;
b = 2;
c = 3;
each[i_, {a,b,c}, i = f[i]]
After the above, {a,b,c}
should evaluate to {f[1],f[2],f[3]}
. Note that that means the second argument to each
should be held unevaluated if it's a list.
If the unevaluated form is not a list, it should evaluate the second argument. For example:
each[i_, Rest[{a,b,c}], Print[i]]
That should print the values of b
and c
.
Addendum: To do for-each properly, it should support Break[]
and Continue[]
. I'm not sure how to implement that. Perhaps it will need to somehow be implemented in terms of For, While, or Do since those are the only loop constructs that support Break[]
and Continue[]
.
And another problem with the answers so far: they eat Return[]
s. That is, if you are using a ForEach loop in a function and want to return from the function from within the loop, you can't. Issuing Return inside the ForEach loop seems to work like Continue[]
. This just (wait for it) threw me for a loop.
I'm years late to the party here, and this is perhaps more an answer to the "meta-question", but something many people initially have a hard time with when programming in Mathematica (or other functional languages) is approaching a problem from a functional rather than structural viewpoint. The Mathematica language has structural constructs, but it's functional at its core.
Consider your first example:
ForEach[i_, {1,2,3},
Print[i]
]
As several people pointed out, this can be expressed functionally as Scan[Print, {1,2,3}]
or Print /@ {1,2,3}
(although you should favor Scan
over Map
when possible, as previously explained, but that can be annoying at times since there is no infix operator for Scan
).
In Mathematica, there's usually a dozen ways to do everything, which is sometimes beautiful and sometimes frustrating. With that in mind, consider your second example:
ForEach[{i_, j_}, {{1,10}, {2,20}, {3,30}},
Print[i*j]
]
... which is more interesting from a functional point of view.
One possible functional solution is to instead use list replacement, e.g.:
In[1]:= {{1,10},{2,20},{3,30}}/.{i_,j_}:>i*j
Out[1]= {10,40,90}
...but if the list was very large, this would be unnecessarily slow since we are doing so-called "pattern matching" (e.g., looking for instances of {a, b} in the list and assigning them to i
and j
) unnecessarily.
Given a large array of 100,000 pairs, array = RandomInteger[{1, 100}, {10^6, 2}]
, we can look at some timings:
Rule-replacement is pretty quick:
In[3]:= First[Timing[array /. {i_, j_} :> i*j;]]
Out[3]= 1.13844
... but we can do a little better if we take advantage of the expression structure where each pair is really List[i,j]
and apply Times
as the head of each pair, turning each {i,j}
into Times[i,j]
:
In[4]:= (* f@@@list is the infix operator form of Apply[f, list, 1] *)
First[Timing[Times @@@ array;]]
Out[4]= 0.861267
As used in the implementation of ForEach[...]
above, Cases
is decidedly suboptimal:
In[5]:= First[Timing[Cases[array, {i_, j_} :> i*j];]]
Out[5]= 2.40212
... since Cases
does more work than just the rule replacement, having to build an output of matching elements one-by-one. It turns out we can do a lot better by decomposing the problem differently, and take advantage of the fact that Times
is Listable
, and supports vectorized operation.
The Listable
attribute means that a function f
will automatically thread over any list arguments:
In[16]:= SetAttributes[f,Listable]
In[17]:= f[{1,2,3},{4,5,6}]
Out[17]= {f[1,4],f[2,5],f[3,6]}
So, since Times
is Listable
, if we instead had the pairs of numbers as two separate arrays:
In[6]:= a1 = RandomInteger[{1, 100}, 10^6];
a2 = RandomInteger[{1, 100}, 10^6];
In[7]:= First[Timing[a1*a2;]]
Out[7]= 0.012661
Wow, quite a bit faster! Even if the input wasn't provided as two separate arrays (or you have more than two elements in each pair,) we can still do something optimal:
In[8]:= First[Timing[Times@@Transpose[array];]]
Out[8]= 0.020391
The moral of this epic is not that ForEach
isn't a valuable construct in general, or even in Mathematica, but that you can often obtain the same results more efficiently and more elegantly when you work in a functional mindset, rather than a structural one.