For example, if x contains {5, 7.2, 9, 0.5, 13} then x[2] is 7.2. Suppose we assign something different to x[2]:
x[2] = {11,22,33}Then x becomes: {5, {11,22,33}, 9, 0.5, 13}. Now if we ask for x[2] we get {11,22,33} and if we ask for x[2][3] we get the atom 33. If you try to subscript with a number that is outside of the range 1 to the number of elements, you will get a subscript error. For example x[0], x[-99] or x[6] will cause errors. So will x[1][3] since x[1] is not a sequence. There is no limit to the number of subscripts that may follow a variable, but the variable must contain sequences that are nested deeply enough. The two dimensional array, common in other languages, can be easily represented with a sequence of sequences:
x = { {5, 6, 7, 8, 9}, -- x[1] {1, 2, 3, 4, 5}, -- x[2] {0, 1, 0, 1, 0} -- x[3] }where we have written the numbers in a way that makes the structure clearer. An expression of the form x[i][j] can be used to access any element, or if you prefer x[i,j] has exactly the same meaning.
(Personally, I use "," when the subscripts have some equivalence, eg points in 3D space deserve [x,y,z], whereas I use "][" when they are logically distinct - almost always the case when one is variable and the other a constant - eg shape[idx][COLOUR].)
The two dimensions are not symmetric however, since an entire "row" can be selected with x[i], but there is no simple expression to select an entire column. There is, however, a library routine to do just that, see columnize() [with columns as a plain integer]. Other logical structures, such as n-dimensional arrays, arrays of strings, structures, arrays of structures etc. can also be handled easily and flexibly:
3-D array:
y = { {{ 1,1}, {3,3}, {5,5}}, {{ 0,0}, {0,1}, {9,1}}, {{-1,7}, {1,1}, {2,2}} } -- y[2][3][1] is 9
Array of strings:
s = {"Hello", "World", "Phix", "", "Last One"} -- s[3] is "Phix" -- s[3][2] is 'h'
A Structure:
employee = { {"John","Smith"}, 45000, 27, 185.5 }To access "fields" or elements within a structure it is good programming style to make up a set of constants that name the various fields. This will make your program easier to read. For the example above you might have:
constant NAME = 1 constant FIRST_NAME = 1, LAST_NAME = 2 constant SALARY = 2 constant AGE = 3 constant WEIGHT = 4You could then access the person’s name with employee[NAME], or if you wanted the last name you could say employee[NAME][LAST_NAME].
Array of structures:
employees = { {{"John","Smith"}, 45000, 27, 185.5}, -- a[1] {{"Bill","Jones"}, 57000, 48, 177.2}, -- a[2] -- .... etc. } -- employees[2][SALARY] is 57000
Accessing Sequence Elements
The number of elements in a sequence can be found by calling the length() function. For example:s = {'a','b','c','d','e'} j = length(s) -- j is now 5Individual elements of s can be referenced using an expression which returns a single positive integer from 1 to length(s), for example:
x = s[1] -- x is now 'a' s[3] = 'Z' -- s is now {'a','b','Z','d','e'}Attempts to reference s[0] or s[6] (and above) cause an index out of bounds error.
Elements of s can also be referenced using -1 to -length(s), counting backwards from the end of the sequence, for example:
x = s[-1] -- x is now 'e' s[-3] = 'c' -- s is now {'a','b','c','d','e'}In this way, negative indexes are simply an exact mirror image (right to left) of the more common (left to right) positive indexes.
Attempts to reference s[-6] and below cause an index out of bounds error.
You can also use the $ shorthand to refer to the last element, for example
x = {{1,2},{3,4}} y = x[$] -- y is now {3,4} y = x[end] -- ditto z = x[$][$] -- z is now 4The last line is equivalent to z = x[length(x)][length(x[length(x)])], and is obviously much clearer and shorter. Exactly the same result is produced by x[-1][-1], x[$][$], and x[end][end].
Dot subscripts are also allowed, eg s.i.j is equivalent to s[i][j]. (provided that constant ORAC in p.exw is set to 1)
Using subscripts to alter a variable defined as a string to contain a non-character will cause a typecheck error. For a variable defined as a sequence that is currently assigned a string, the same operation will quietly auto-expand the string (one byte per character) to a dword-sequence so that the substitution can take place.
Phix data structures are almost infinitely flexible. Arrays in other languages are constrained to have a fixed number of elements, and those elements must all be of the same type. Phix eliminates both of those restrictions. You can easily add a new structure to the employee sequence above, or store an unusually long name in the NAME field and phix will take care of it for you. If you wish, you can store a variety of different employee "structures", with different sizes, all in one sequence.
Not only can a phix program easily represent all conventional data structures but you can create very useful, flexible structures that would be extremely hard to declare in a conventional language. See Phix vs Conventional Languages.
In general any expression may be subscripted, for example it would be perfectly legal to write "AEIOU"[vowel_number], however this is not compatibile with RDS Euphoria or OpenEu, plus it could be quite wasteful to write something like {5+2,6-1,7*8,8+1}[3]. There are some exceptions, for example you may not immediately follow a slice (see next) with a subscript. (You could use parenthesis as a work-round, eg (s[2..4])[2] is equivalent to s[3], however the latter would be significantly faster, as well as being much easier to read and write in the first place.)