Getting Started | Documentation | Glish | Learn More | Programming | Contact Us |
Version 1.9 Build 1556 |
|
While Glish supports the ``usual" form of single-element vector access familiar to C and FORTRAN programmers, it also provides ways for accessing or modifying more than one vector element at a time.
Glish vector indices needn't be scalar values; the indices can also be multi-element vectors. The indices have different meanings depending upon whether their type is integer or boolean. Each is discussed below.
If the index's type is integer (or numeric and hence convertible to integer; but not boolean), then the values of the index indicate the desired elements of the indexed vector. For example, if we have
a := [5, 9, 0, -3, 7, 1] b := [4, 2]then
a[b]yields the vector
[-3, 9]Because -3 is the 4th element of a and 9 is the 2nd element. There's no special need for the vector index to be a variable; it can also be a constant:
a[[4,2]](which is equivalent to a[b]) or a vector-valued expression:
a[b+2]yields
[1, -3]because these are the 6th and 4th elements of a.
Because the : operator yields an integer vector, you can use it to access a contiguous sequence of elements in a vector:
a[3:5]yields
[0, -3, 7]because these are the 3rd through 5th elements of a. Similarly,
a[2:1]yields
[9, 5]as these are the 2nd and 1st elements of a. If you have a vector x and you want to reverse the order of its elements, you can do this like:
rev_x := x[len(x):1]
The ind function provides a convenient way for generating a vector value's indices:
ind(x)is equivalent to:
1:len(x)
The seq function (see § 10.3, page ) provides a flexible way to generate vector indices. This function takes one, two, or three arguments. If seq is invoked with just one scalar argument then it returns a vector of the integers from 1 to that value, for example
seq(7)yields
[1, 2, 3, 4, 5, 6, 7]If seq is invoked with a single non-scalar argument it returns a vector of the integers from 1 to the length of the argument:
seq([3, 1, 4, 1, 5, 9])yields
[1, 2, 3, 4, 5, 6]
If seq is invoked with two arguments it returns the integers between the two, inclusive:
seq(5,2)yields
[5, 4, 3, 2]If the first argument is a non-scalar, the first element is used to determine where the sequence begins.
If invoked with three arguments seq returns the integers between the first two using the third as a stride. Starting with the first value it works its way to the second, each time incrementing by the stride. It stops when it passes the second argument. So
seq(3,10,2)yields
[3, 5, 7, 9]and
seq(20,8,-4)yields
[20, 16, 12, 8]while
x[seq(1,len(x),2)]yields every other element of x. Note that in the second example, using
seq(20,8,4)instead would result in a run-time error. If a stride is given, it must reflect the direction the sequence will proceed.
A boolean vector index forms a mask that selects those elements for which the mask is true. For example,
a := "hello there, how are you?" print a[[F,T,T,F,F]]prints ``there, how". Similarly,
y := x[x > 5 & x < 12]assigns to y a vector of only those elements of x that are greater than 5 and less than 12. The expression x > 5 & x < 12 returns a boolean mask that is true for those elements of x greater than 5 and less than 12, and false for the remainder. Another example:
max(x[x < 10])returns the largest element of x that is less than 10. (See § 10.3, page for a discussion of max and other related functions.)
Often you want to know the indices of vector elements with a certain property, rather than the values of those elements. The following illustrates the idiom for doing so:
neg_indices := ind(x)[x < 0]Here you assign to
neg_indices
the indices of those
elements of x that are less than 0. Thus
x[neg_indices]and
x[x < 0]are equivalent expressions.
Boolean indices must have the same number of elements as the indexed vector, otherwise a run-time error occurs.
In addition to using vector indices to access multiple vector elements, you can also use them to modify multiple elements.
a[[5,3,7]] := 10:12assigns to the 5th, 3rd, and 7th elements of a the numbers 10, 11, and 12, respectively. The right-hand-side of the assignment can also be a scalar value:
a[[5,3,7]] := 0sets those same elements to 0.
Similar operations can be accomplished using masks:
a[a > 7] := 32changes all elements of a that are greater than 7 to 32, and
x[x < 0] := -x[x < 0]is the same as
x := abs(x)indeed, this is how abs is implemented; it converts the negative elements of x to their absolute value. (See § 10.3, page , for a discussion of abs and other related functions.)
As with simple scalar assignments, the types on both sides of the := operator must be compatible, as discussed in § 3.1.3, page .
The right-hand-side must either be a scalar or have the same number of elements as indicated by the indices or mask used on the left-hand-side. For example,
a[1:3] := [2,4]is not allowed.
As with vectors, you can access and modify multiple record fields using multi-element indices. For records the index must be a vector of strings. For example,
a := [foo=1, bar=[3.0, 5.3, 7], bletch="hello there"] b := a[["foo", "bar"]]assigns to b a record that has a foo field with the integer value 1 and whose bar field is the double vector [3.0, 5.3, 7.0]. Because of the way double-quoted string literals are broken up into a vector (see § 3.3.1, page ), the second statement could also have been written:
b := a["foo bar"]
You can assign multiple record fields in a similar fashion:
a["foo bar"] := [x=[9,1], y=T]changes a's foo field to be the integer vector [9,1], and a's bar field to the boolean value T. You can also make similar assignments by accessing multiple-field elements on the right-hand-side. For example, the following is equivalent:
r := [x=[9,1], y=T, z="ignore me"] a["foo bar"] := r["x y"]For the assignment to be legal, the right-hand-side must be a record with the same number of fields as the left-hand-side (as in the example above). The field names are ignored, and the assignment is done field-by-field, left-to-right.
As discussed in § 3.4.4, page , you can access records using numeric subscripts, and you can use multiple numeric subscripts to access and modify more than one field in the record. For example, the following reverses the fields of r:
r := [x=1, y=T, z="hello"] r[3:1] := rnow r.x is "hello", r.y remains T, and r.z is 1.