each (:E) / peach
Syntax
or
or
Arguments
func is a function.
args … are the required parameters of func.
X / Y can be scalar/vector/matrix/table.
Details
Apply a function to each element of args…. For matrices, apply a function to each column; for tables, apply a function to each row.
The difference between func(X) and func :E X is that the former treats X as the one input variable while the later takes each element in X as an input variable. We should avoid using “:E” if we can find corresponding vector functions since element-wise operations are very slow with a large number of elements.
peach
is the parallel computing version of template function each
. For tasks that take a long time to finish, peach
can save a significant amount of time over each
. For light tasks, however, peach
may take longer than each as the overhead of parallel function call is not trivial.
Examples
Suppose we need to calculate the daily compensation for 3 workers. Their working hours are stored in vector x=[9,6,8]. Their hourly rate is \(10 under 8 hours and \)20 beyond 8 hours. Consider the following function wage
:
$ x=[9,6,8]
$ def wage(x){if(x<=8) return 10*x; else return 20*x-80}
$ wage x;
The vector can't be converted to bool scalar.
wage(x) does not return a result, as x<=8, i.e., [9,6,8]<=8 returns a vector of conditions [0,1,1], not a scalar condition that is required by if
.
In contrast, consider the following solutions:
$ each(wage, x);
[100,60,80]
$ wage :E x;
[100,60,80]
$ def wage2(x){return iif(x<=8, 10*x, 20*x-80)};
// the iif function is an element-wise conditional operation
$ wage2(x);
[100,60,80]
Similarly, each
can also be applied to a function with more than one parameter.
$ def addeven(x,y){if (x%2==0) return x+y; else return 0}
$ x1=1 2 3
$ x2=4 5 6;
$ each(addeven, x1, x2);
[0,7,0]
each
with a tuple:
$ t = table(1 2 3 as id, 4 5 6 as value, `IBM`MSFT`GOOG as name);
$ t;
id |
value |
name |
---|---|---|
1 |
4 |
IBM |
2 |
5 |
MSFT |
3 |
6 |
GOOG |
$ each(max, t[`id`value]);
[3,6]
each
with matrices:
$ m=1..12$4:3;
$ m;
col1 |
col2 |
col3 |
---|---|---|
1 |
5 |
9 |
2 |
6 |
10 |
3 |
7 |
11 |
4 |
8 |
12 |
$ each(add{1 2 3 4}, m);
// note add{1 2 3 4} is a partial application, which adds [1, 2, 3, 4] to each of the 3 columns
col1 |
col2 |
col3 |
---|---|---|
2 |
6 |
10 |
4 |
8 |
12 |
6 |
10 |
14 |
8 |
12 |
16 |
$ x=1..6$2:3;
$ y=6..1$2:3;
$ x;
col1 |
col2 |
col3 |
---|---|---|
1 |
3 |
5 |
2 |
4 |
6 |
$ y;
col1 |
col2 |
col3 |
---|---|---|
6 |
4 |
2 |
5 |
3 |
1 |
$ each(**, x, y);
[16,24,16]
// 比如,24=3*4+4*3
In the example below, we use the function call
in a partial application that applies each of [sin, log] to vector 1..3
// when "functionName" is empty, it will be filled with function names dynamically.
$ each(call{, 1..3},(sin,log));
sin |
log |
---|---|
0.841471 |
0 |
0.909297 |
0.693147 |
0.14112 |
1.098612 |
Performance Note
Template :E (each)
is not recommended when there is a large number of elements. In those scenarios we should look for more efficient vector solutions.
$ x=rand(16, 1000000);
$ timer(10){each(wage, x)};
Time elapsed: 38164.9 ms
$ timer(10){iif(x<8,10*x,20*x-80)};
Time elapsed: 81.516 ms