Arrays

From RFO-BASIC! Manual
Manual contents (Statement index)
Language features The basicsArraysData structuresInterrupt routinesUser-defined functions
Interfaces Audio playerBluetoothFilesGraphicsHTMLKeyboardSocketsSQLTelecom
Programming notes Coexisting with Android

Arrays are sequences of numeric variables or of string variables (each is an element of the array), in which each element is identified by number. The first element is element number 1 (not element number 0, as in C language). Arrays are the easiest way to write code in which the variable affected varies depending on a counting number.

A BASIC program creates an array with the DIM statement discussed below. Certain BASIC statements that return multiple values can create arrays to hold the values. Others require that the array already exist.

When you create a string array, elements that are not yet assigned a value have the value of the empty string. When you create a numeric array, elements that are not yet assigned a value have the value of 0.

Syntax

The name of an array can be the name of a numeric variable (such as A), in which every element is a numeric value; or a string variable (such as A$), in which every element is a string value.

The simplest array is an array of one dimension (a vector or linear array). If the variable A is a linear array of ten elements, its elements are referenced as A[1] through A[10]. The number inside the brackets is called the index and specifies the array element to be used. The index does not have to be a numeric constant, but can be any numeric expression. The expression A[I] operates on a different element depending on the value of I. In this way, you can write code that refers to different array elements at different times.

A two-dimensional array (a matrix) can be imagined as a table. All references to this array have two indexes (or "subscripts"). The first might be the row in the table and the second might be the column. So B[3, 5] might represent information in the table's third row, fifth column.

Segments

You can specify a segment of a one-dimensional array using this same syntax. The first index is the element at which to start, and the second index is the number of elements in the segment. So A[3, 5] means an array segment containing A[3], A[4], A[5], A[6], and A[7]. Omitting the first index (such as A[, 5]) assumes 1, which starts at element 1 of the array. Omitting the second index (such as A[4, ]) continues to the end of the array. Therefore, omitting both (such as A[,] denotes the entire array. The syntax A[] also denotes the entire array.

Wherever this chapter specifies a vector or describes a parameter with a name ending in _vec, it can be either an entire one-dimensional array, or a segment using the two-index syntax shown above.

The segment syntax doesn't apply to all arrays, only those DIM creates with a single dimension, when the program refers to them with two indexes instead of one. For example, if you create a matrix, there is no built-in syntax with which to specify a sub-matrix of it, though you can create a second matrix and copy entries to build such a sub-matrix.

Implementation

When an RFO-BASIC! program creates an array, BASIC obtains memory from the Android device, sufficient to store each element, plus a bookkeeping area in which BASIC remembers the size of the array. There is no limit on the number of dimensions a BASIC array can have, nor on the number of elements in each dimension. The only inherent limitation on the size of an array is the available memory of the Android device.

See also
  • Lists are similar to one-dimensional arrays, but additional BASIC statements add helpful operations, such as insert and delete, where subsequent elements shift position.
  • Arrays are always passed to user-defined functions by reference, which means that code inside the function can read and modify any element of the array.
  • The LIST.ADD.ARRAY statement builds a list from values contained in an array.
  • The GR.SET.PIXELS draws a figure onto the Graphics Screen using x and y coordinates contained in an array.

Creating arrays[edit]

DIM[edit]

Create one or more arrays

Syntax
DIM arrayspec{, arrayspec}...

where each arrayspec is:

<variablename>[<dim1_nexp>{,<dim2_nexp>}...]
Description

The DIM statement creates one or more arrays as specified in the statement. Each numeric expression specifies how many elements the array will have in that dimension. The number of numeric expressions following a variable specifies how many dimensions the array will have.

A single DIM statement can create many arrays. Each can be either a numeric array or a string array. When RFO-BASIC! creates an array, it obtains memory from the Android device and initializes each element of the array. Elements of numeric arrays are initialized to 0 and elements of string arrays are initialized to the empty string.

Examples
DIM A[15]
DIM B$[2,6,8], C[3,1,7,3], D[8], E[3, 4]

The first example creates a one-dimensional numeric array (vector) with fifteen elements (A). The second example creates a three-dimensional string array (B$), a four-dimensional numeric array (C), a one-dimensional numeric array (D), and a two-dimensional numeric array (E).

ARRAY.LOAD[edit]

Create a one-dimensional array and specify its initial values

Syntax
ARRAY.LOAD <variablename>[], <exp>, ...

The ARRAY.LOAD statement creates a new, one-dimensional array with the specified <variablename>. Unlike DIM, the writer does not specify the number of elements of the new array with a numeric expression between the brackets. Instead, it follows the brackets with a list of expressions. Each expression is loaded into an element of the new array, starting with element number 1. The size of the new array is the number of expressions in the list.

If the named array already exists, it is overwritten.

The array may be numeric (such as A[]) or string (such as A$[]). Each expression in the following list must be the same type as the array.

The list of expressions may be continued onto the next line by ending the line with the ~ character. The ~ character may be used between <exp> parameters where a comma would normally appear. The ~ itself separates the parameters; the comma is optional. The ~ character may not be used within a parameter to split it between two lines.

Examples
ARRAY.LOAD Numbers[], 2, 4, 8 , n^2, 32
ARRAY.LOAD Hours[], 3, 4,7,0, 99, 3, 66~        % comma not required before ~
37, 66, 43, 83,~                                % comma is allowed before ~
83, n*5, q/2 +j
ARRAY.LOAD Letters$[], "a", "b","c",d$,"e"

ARRAY.COPY[edit]

Copies values from a vector to a one-dimensional array, possibly adding new elements

Syntax
ARRAY.COPY <source_array_vec>, <dest_array_name>[{<start_or_extras_nexp>}]
Description

The ARRAY.COPY statement copies elements of the existing array named by <source_array_vec> to <dest_array_name>. The arrays must either both be string arrays or both be numeric arrays. The <source_array_vec> can be an entire array (such as SourceArray[]) or a segment (such as SourceArray[start, length]).

If <dest_array_name> does not exist, then ARRAY.COPY creates it. If ARRAY.COPY includes <start_or_extras_nexp>, then all the specified elements are copied to it, and it also receives extra elements. Their initial values will be 0 in the case of a numeric array, or the empty string in the case of a string array.

  • If <start_or_extras_nexp> is positive, then the specified number of elements are created after the elements copied from <source_array_vec>.
  • If <start_or_extras_nexp> is negative, then the (positive) specified number of elements are created at the start of the new array, and all the elements copied from <source_array_vec> will be placed after them.

If <dest_array_name> already exists, then ARRAY.COPY overwrites some or all of its elements with values from <source_array_vec>. If <start_or_extras_nexp> exists, it specifies the position in <dest_array_name> where the copying is to begin. The statement may specify a different number of values to copy than the available space in <dest_array_name>. The statement ends without error if it reaches the end of either <source_array_vec> or <dest_array_name>.

Example

The program Sample_Programs/f26_array_copy.bas, included with the RFO-BASIC! installation, contains working examples of the ARRAY.COPY statement.

ARRAY.FILL[edit]

Fill a vector with a specified single value

Syntax
ARRAY.FILL <array_vec>, <value_exp>
Description

The ARRAY.FILL statement sets each element of a vector to the value of <value_exp>. The specified array must already exist. The <array_vec> can be an entire array (such as A[]) or a segment (such as A[start, length]). Either the vector and the expression must both be numeric or they must both be string.

Deleting arrays[edit]

Syntax
UNDIM <a_arrayname>{, ...}
ARRAY.DELETE <a_arrayname>{, ...}
Description

The UNDIM and ARRAY.DELETE statement are equivalent statements. Both delete one or more specified arrays. Deleting an array releases back to the Android device the memory that the array used. The array name cannot be used except if it is explicitly or implicitly created again. At that time, it does not need to have the same dimensions as it had before.

Testing arrays[edit]

Two RFO-BASIC! statements let a program examine arrays it has already created:

ARRAY.DIMS <source_array>[]{, {<dims_array>[]}{, <num_dims_nvar}}

The ARRAY.DIMS statement indicates how many dimensions <source_array> has and how many elements it has in each dimension. This array must already exist.

If <num_dims_nvar> is provided, ARRAY.DIMS sets it to the number of dimensions of <source_array>.

If <dims_array> is provided, ARRAY.DIMS sets elements of it to the length of <source_array> in each dimension. If <dims_array> exists, it must be a one-dimensional numeric array, and you cannot specify a segment. If <dims_array> does not exist, ARRAY.DIMS creates it with a number of elements equal to the number of dimensions of <source_array>.

ARRAY.LENGTH <length_nvar>, <source_array>

The ARRAY.LENGTH statement returns, in <length_nvar>, the number of elements in <array_vec>.

  • If <source_array> is a one-dimensional array, then this is its length, whether given in the DIM statement or by later extensions.
  • If <source_array> is a one-dimensional array but you specify two subscripts to indicate a segment (such as A[start, length]), then this is the length of the segment. (If length is provided, this is the result, except when there are fewer elements remaining in the array.)
  • If <source_array> is a multi-dimensional array, then this is the product of the array's length in each of its dimensions. For example, if you wrote DIM A[5, 2, 4], then ARRAY.LENGTH would multiply to compute the value 40.

String operations[edit]

Two RFO-BASIC! statements parse a string into an array, and assemble an array into a string.

It is usually most efficient to split a string into pieces, operate on the pieces, and reassemble the pieces into a string. Even considering the two additional steps of converting the form of the data, the total computation is many times faster than operating on substrings in interpreted BASIC code, such as with a FOR loop.

SPLIT[edit]

Split a string into pieces and populate an array with them

Synopsis
SPLIT{.ALL} <result_sarr>$[], <source_sexp>{, <separator_sexp>}
Description

The SPLIT statement analyzes a string expression <source_sexp>, breaks it into pieces (normally, words), and assigns each word to an element of the one-dimensional string array <result_sarr>. The characters $[] are required. If this array exists, SPLIT overwrites it; otherwise, SPLIT creates a new array.

The SPLIT statement looks for a separator to define the pieces of the source string. Normally, the separator is any white space (one or more spaces, tabs, or separator characters), so the pieces of the string are discrete words of text; any punctuation not separated by white space is included in this "word." You can specify a different separator by providing the optional third parameter. It is a UNIX Regular Expression (or RE; as defined in http://developer.android.com/reference/java/util/regex/Pattern.html), a language often used for pattern-matching.

REs often use the backslash character, \. Since you are passing an RE to SPLIT as a BASIC string, you must type \\ for each desired backslash.

Here are some interesting values for <separator_sexp>:

  • "\\s+" means match on any white space, which is the same effect as omitting this parameter entirely.
  • "\\\\|" is a regular expression that matches on anything. Its effect is to divide <source_sexp> into individual characters and put each one in a separate array element.
  • ":" is used in the example below to indicate that : is the separator.

The following rules describe cases where array elements are set to the empty string:

  • If the source string begins with the separator, then there is an implicit null first piece, so the first element of the array gets the empty string. (The WORD$() function works differently; it strips leading and trailing occurrences of the separator before splitting the string.)
  • If the separator occurs twice in a row (with nothing between them), then the piece of the string between them is null, and the corresponding element of the array gets the empty string. (White space cannot occur twice in a row. Any run of white space is matched by "\\s+".)
  • If the string ends with one or more occurrences of the separator:
    • The SPLIT statement does not create corresponding elements of the array.
    • The SPLIT.ALL statement does create one element of the array for each null trailing piece.
    • (Again, the WORD$() function strips trailing occurrences of the separator.)
Example

This example uses : as the separator. Thus, there is an empty piece at the start, one in the middle, and one at the end of the string.

string$ = ":a:b::c:d:"
SPLIT result$[], string$, ":"

ARRAY.LENGTH length, result$[]
FOR I = 1 TO length
 PRINT "{" + result$[i] + "}";
NEXT I
PRINT

The output is {}{a}{b}{}{c}{d}. But SPLIT.ALL would include a seventh array element for the trailing null piece, and the test program would output {}{a}{b}{}{c}{d}{}.

JOIN[edit]

The JOIN statement does the reverse of SPLIT: It assembles elements of a string array into a single string.

Synopsis
JOIN{.ALL} <source_sarr>$[], <result_svar>{, <separator_sexp>{, <wrapper_sexp>}}
Description

The JOIN statement assembles the elements of the one-dimensional string array <source_sarr> into the single string <result_svar>.

The JOIN statement ignores elements of <source_sarr> that are the empty string. The JOIN.ALL statement includes them.

Each relevant element of <source_sarr> provides one piece of the result string:

  • If you provide the parameter <separator_sexp>, BASIC adds this separator string after each piece except the last.
  • If you provide the parameter <wrapper_sexp>, BASIC adds this wrapper string to the start of the assembled string, and again to the end.

If using double quote in the separator or wrapper, keep in mind that, in RFO-BASIC literals, you must escape it to keep BASIC from interpreting it as the end of the string. That is, render it as \". Enclose the entire thing in double quotes to form a valid literal.

Example

This example uses both the SPLIT statement described above and the JOIN statement. It produces a string in the CSV format (comma-separated values), with each value quoted with double quotes. So we want the separator between values to be "," (a double quote to end the preceding piece and another to introduce the following piece) and the wrapper at the start and end of the result to be ".

InnerPlanets$ = "Mercury Venus Earth Mars"  % Each planet a "word"
SPLIT IP$[], InnerPlanets$                  % Get one planet in each array element
JOIN IP$[],  CSV$,  "\","\"",  "\""         % Create a CSV string
PRINT CSV$

The output from this test program is:

"Mercury","Venus","Earth","Mars"

As another example, this code simply reverses the characters in the variable var$:

SPLIT tmp$[], var$, "\\\\|"    % Separate each character!
ARRAY.REVERSE tmp$[]           % See Vector operations below
JOIN  tmp$[], var$             % No separator, no wrapper

It is not only more elegant and readable than stepping through the string in a FOR/NEXT loop but many times faster.

Vector operations[edit]

Three RFO-BASIC! statements easily perform common operations on a vector. A vector is a one-dimensional array or a segment of one, as explained above in the overview. Since these operations do not require repeat interpretation, they are much more efficient than coding a BASIC loop to perform the computations.

Arithmetic[edit]

When a one-dimensional numeric array, or segment of one, exists and contains a series of numbers, several RFO-BASIC! statements easily perform arithmetic on this series.

ARRAY.MAX <max_nvar>,<array_vec>
Sets <max_nvar> to the highest value within <array_vec>.
ARRAY.MIN <min_nvar>,<array_vec>
Sets <min_nvar> to the lowest value within <array_vec>.
ARRAY.STD_DEV <sd_nvar>,<array_vec>
Sets <sd_nvar> to the standard deviation of the elements of <array_vec>.
ARRAY.SUM <sum_nvar>,<array_vec>
Sets <sum_nvar> to the sum of the elements of <array_vec>.
ARRAY.VARIANCE <v_nvar>,<array_vec>
Sets <v_nvar> to the variance of the elements of <array_vec>.

ARRAY.SEARCH[edit]

Search a vector

Syntax
ARRAY.SEARCH <array_vec>, <value_exp>, <pos_nvar>{, <start_nexp>}
Description

The ARRAY.SEARCH statement searches <array_vec> for the first occurrence of <value_exp> and returns in <pos_nvar> the number, relative to the start of the vector, of this first occurrence. If <value_exp> does not occur in the area searched, the statement sets <pos_nvar> to 0.

If <array_vec> is a one-dimensional array, then <pos_nvar> is the position of the occurrence. If <array_vec> is a segment, then it is the position relative to the start of the segment.

If <start_nexp> is present, then the search does not start at the start of the vector, but that many elements into the vector.

ARRAY.SEARCH conducts an exact search, with no heuristics such as rounding or treating capital and lowercase letters as equivalent.

Example
ARRAY.SEARCH A[15,6], 9999, i, 3

The vector to search is the segment consisting of the six elements A[15] through A[20]. The search begins at element number 3 of this segment; that is, at A[17]. Therefore, ARRAY.SEARCH examines elements A[17] through A[20]. It can set i to 3, 4, 5, or 6; or 0 if none of the four equals the desired value 9999.

Modification[edit]

The statements in this section change the values of elements of numeric or string vector. If the vector is a segment, then elements outside that segment are never changed.

ARRAY.SORT <array_vec>
The ARRAY.SORT statement puts the values in the segment in ascending order. If there are duplicate values in the segment, there will still be duplicate values after executing ARRAY.SORT.
ARRAY.REVERSE <array_vec>
The ARRAY.REVERSE statement puts the values in the segment in reverse order to the order they occupied at the start.
ARRAY.SHUFFLE <array_vec>
The ARRAY.SHUFFLE statement puts the values in the segment in random order.

Sources[edit]