Water 5-Getting Started and Examples-Level 1 Examples
Transpose is a mathematical operation on a 2 dimensional array or vector that
"rotates" the array.
Given a 2d vector like: <v <v 1 2 3 4/> <v 5 6 7 8/>/>
returns a 2d vector like: <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/>
The resulting vector is also two dimensional and has the same inner
elements as the original but they are arranged differently as you can see.
First you need to know that the method "v" creates a vector of its arguments.
You can access those arguments within the returned vector like so:
<v 5 6 7 8/>.1
6
Note that Water vectors are zero-based so:
<v 5 6 7 8/>.0
5
If we have a two dimensional vector, we can access an element down inside the
inner dimension by adding another part to the path that accesses values.
<v <v 1 2 3 4/> <v 5 6 7 8/>/>.0.1
 | 2 |
<v <v 1 2 3 4/> <v 5 6 7 8/>/>.1.3
 | 8 |
Here's the complete definition for transpose plus a call to it and the expected result:
(Note that Water has a build-in transpose method. See bottom of file for details.)
<method transpose vec2d=req>
vec2d.0.<length/>.<for_each combiner=insert>
<set key_to_get=value/>
vec2d.<for_each combiner=insert>
value.<get key_to_get/>
</for_each>
</for_each>
</method>
<transpose <v <v 1 2 3 4/> <v 5 6 7 8/>/>/> | <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/> |
Even though this code is only a few lines long and uses very common Water methods,
it is still difficult to understand if you're not familiar with Water, so below
is an expression by expression explanation of what's going on.
<method transpose vec2d=req/>
transpose is a global method that takes one required argument,
a two dimensional vector named 'vec2d'.
Most of the work in this algorithm is performed by the for_each method.
It has a lot of functionality but we'll only describe those parts of it that are used
in this example. See the documentation on for_each for more functionality.
If you give for_each a subject of an integer, that tells for_each how many times to loop.
In each loop iteration, the code in the content of a call to for_each is executed with
the variables 'key' and 'value' bound to objects from the subject that are being looped over.
For our outer call to for_each, we are going to loop for
vec2d.0.<length/> times, which, in this case, is 4 because we're taking the length of 1234
Now in the content of the outer for_each we take the 'value' variable that is bound to
0, 1, 2, or 3, depending on which iteration we're on,
and bind it to 'key_to_get' because we are going to do ANOTHER inner for_each that
will rebind the variable value. So we stick the OUTER value into another variable
to save it away for use in the inner for_each content.
OK now for the inner for_each call, we're giving it a subject of
vec2d. Since vec2d is not an integer for_each does something different than the outer for_each call.
For_each will loop over the elements of vec2d.
During the first inner iteration, 'value' will be bound to <v 1 2 3 4/> and the second
time 'value' will be bound to <v 5 6 7 8/>
The entire body of code to execute for the inner for_each is just the one-liner:
value.<get key_to_get/>
During the first iteration, value will be bound to <v 1 2 3 4/>
and key_to_get will be bound to 0.
Normally to get an element out of a vector we just
have to say something like myvec.0
But in this case we need to get the value at an index that varies
so our index is in a variable and we've got to evaluate that variable
to get the proper index.
The "get" method essentially performs the functionality of dot in Water
except that you can evaluated the key to 'get' so:
<v 100 101 102/>.<get <plus 1 1/>/>
 | 102 |
<plus 1 1/> executes to 2 so we get the value of the 2 key within the
vector which is 102.
Our first iteration performs:
<v 1 2 3 4/>.<get 0/>
which is effectively
<v 1 2 3 4/>.0
which results in 1.
Unlike looping constructs in most popular languages, for_each always
returns a value. By default it returns the value of the last expression of the last iteration.
By using a "combiner" method we can aggregate the results
of each iteration. Using 'insert' as our combiner method lets us make a vector of
all the results, so first we execute <v 1 2 3 4/>.0 and collect 1, then
our 2nd pass through the inner for_each returns:
<v 5 6 7 8/>.<get 0/>
which results in 5.
So when our inner call to for_each is all done with its 2 iterations, it returns
a vector of <v 1 5/>
Now we pop back out into our outer for_each whose first iteration results in
<v 1 5/> , i.e. the returned value from the inner for_each.
Since the outer for_each also has combiner=insert, it makes this
<v 1 5/> be the first element in a new vector and
calls our inner for_each again which, this time,
has key_to_get bound to 1.
That means in our inner for_each calls, effectively
<v 1 2 3 4/>.<get 1/> which returns 2
and
<v 5 6 7 8/>.<get 1/> which returns 6,
both of which get combined in a vector of <v 2 6/>
which is returned to the outer for_each that then takes the <v 2 6/>
and inserts it into the end of the vector we're building there
to make <v <v 1 5 /> <v 2 6/> /> as our for_each result computed so far.
After a couple more iterations of the outer loop we are finally done
to return <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/>
Here's what it looks like to just call it:
<transpose <v <v 1 2 3 4/> <v 5 6 7 8/>/> />
 | <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/> |
If we transpose the result of a call to transpose we get back the
2d vector that we started with:
<transpose <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/>/>
 | <v <v 1 2 3 4/> <v 5 6 7 8/>/> |
Transpose is the kind of operation that is often called on large vectors so
it needs to be fast. We have build-in to Water a faster version of transpose.
It is a method on vectors so it is called like so:
<v <v 1 2 3 4/> <v 5 6 7 8/>/>.<transpose/>
 | <v <v 1 5/> <v 2 6/> <v 3 7/> <v 4 8/>/> |
By having transpose take its vector as the subject, it is easier to
call transpose twice to get back the original vector.
You'd do this to verify that transpose actually works :-)
<v <v 1 2 3 4/> <v 5 6 7 8/>/>.<transpose/>.<transpose/>
 | <v <v 1 2 3 4/> <v 5 6 7 8/>/> |
© Copyright 2006 Clear Methods, Inc.