loadPackage OK for extension/stringChunk.cls
loadPackage OK for utilities/indentedStream.cls
loadPackage OK for extension/extensions.cls
loadLibrary OK for rxunixsys
loadPackage OK for ncurses.cls
loadPackage OK for csvStream.cls
loadLibrary OK for hostemu
loadPackage OK for json.cls
loadPackage OK for mime.cls
loadPackage OK for rxftp.cls
loadLibrary OK for rxmath
loadPackage OK for rxregexp.cls
loadPackage OK for regex/regex.cls
loadPackage OK for smtp.cls
loadPackage OK for socket.cls
loadPackage OK for streamsocket.cls
loadPackage OK for pipeline/pipe.cls
loadPackage OK for rgf_util2/rgf_util2.rex
loadPackage OK for BSF.CLS
loadPackage OK for oorexxshell_queries.cls
loadPackage OK for pipeline/pipe_extension.cls
loadPackage OK for rgf_util2/rgf_util2_wrappers.rex

REXX-ooRexx_4.3.0(MT)_64-bit 6.04 6 Sep 2023
Input queue name: Sba04Q600001ce30c0

--------------------
-- Array programming
--------------------

/*
rank

APL R←⍴⍴Y
An array may have 0 or more axes or dimensions.
The number of axes of an array is known as its rank.
An array with 0 axes (rank 0) is called a scalar
An array with 1 axis (rank 1) is called a vector.
An array with 2 axes (rank 2) is called a matrix or table.
An array with 3 axes (rank 3) is called a cube.
An array with more than 2 axes is called a multi-dimensional array
*/

/*
shape

APL R←⍴Y (Rho)
The shape of a scalar is an empty vector []
The shape of an array is an array which gives the size of each dimension.
*/

/*
Any object other than an array is a scalar.
In particular, a string is a scalar, not an array as in APL.
Special case which does not exist in APL : The rank of an array with no dimension yet assigned is -1.
*/

-- scalar
ooRexx[sh]> "string"~shape=
[]
ooRexx[sh]> "string"~rank=
 0

-- array with no dimension
ooRexx[sh]> .array~new~shape=
an Array (shape [], 0 items)
ooRexx[sh]> .array~new~rank=
-1

/*
The helper v(...) creates a vector.
*/

-- empty vector
ooRexx[sh]> v()=
[]
ooRexx[sh]> v()~rank=
 1

-- vector of 3 items
ooRexx[sh]> v(0,1,2)~shape=
[ 3]
ooRexx[sh]> v(0,1,2)~rank=
 1

/*
The helper a(...) creates an empty array of specified dimensions.
It's almost similar to .array~new(...), except for a() which returns an array with 0 dimension (a scalar).
Once the number of dimension(s) is fixed, it's no longer possible to change it.
This is different from .array~new which returns an array without dimension.
The number of dimension(s) will be determined by the first access to the array:
a = .array~new; say a[]        -- Not enough positional arguments for method; 1 expected
a = .array~new; say a[1]       -- 1 dimension
a = .array~new; say a[1,1]     -- 2 dimensions
*/

-- array with 0 dimension (scalar)
ooRexx[sh]> nodim = a()
ooRexx[sh]> nodim=
an Array (shape [], 0 items)
ooRexx[sh]> nodim~rank=
 0

-- you can't use any index with such array
ooRexx[sh]> nodim[1]=
Too many subscripts for array; 0 expected.
Error code= 93.926

-- but no index is ok
ooRexx[sh]> nodim[]=
(The NIL object)
ooRexx[sh]> nodim[] = "hello!"
ooRexx[sh]> nodim[]=
'hello!'

-- empty vector of shape 5
ooRexx[sh]> a(5)~shape=
[ 5]
ooRexx[sh]> a(5)~rank=
 1

-- empty matrix of shape 2,2
ooRexx[sh]> a(2,2)~shape=
[ 2, 2]
ooRexx[sh]> a(2,2)~rank=
 2

-- empty cube of shape 3,3,3
ooRexx[sh]> a(3,3,3)~shape=
[ 3, 3, 3]
ooRexx[sh]> a(3,3,3)~rank=
 3

/*
The instance method array~of is an initializer which takes into account the dimensions (shape) of the array.

Rules inspired by APL :
If there are too many items, the extra items are ignored.
If there are fewer items than implied by the dimensions, the list of items is reused as many times as necessary to fill the array.
*/
ooRexx[sh]> a(6)~of(1,2,3)=
[ 1, 2, 3, 1, 2, 3]
ooRexx[sh]> a(2,3)~of(1,2,3)=
an Array (shape [2,3], 6 items)
[ 1, 1] :  1
[ 1, 2] :  2
[ 1, 3] :  3
[ 2, 1] :  1
[ 2, 2] :  2
[ 2, 3] :  3
ooRexx[sh]> a(6)~of(1,2,3,4,5,6,7,8,9)=
[ 1, 2, 3, 4, 5, 6]
ooRexx[sh]> a(2,3)~of(1,2,3,4,5,6,7,8,9)=
an Array (shape [2,3], 6 items)
[ 1, 1] :  1
[ 1, 2] :  2
[ 1, 3] :  3
[ 2, 1] :  4
[ 2, 2] :  5
[ 2, 3] :  6

/*
If there is only one argument, and this argument has the method ~supplier then each item returned by the argument's supplier is an item.
*/
ooRexx[sh]> a(2,3)~of(.object~methods~allIndexes~sort)=
an Array (shape [2,3], 6 items)
[ 1, 1] : ''
[ 1, 2] : ' '
[ 1, 3] : '<>'
[ 2, 1] : '='
[ 2, 2] : '=='
[ 2, 3] : '><'

/*
If there is only one argument, and this argument is a doer, then the doer is called for each cell to initialize.
The value returned by the doer is the item for the current cell.
If no value returned then the cell remains unassigned.
*/
ooRexx[sh]> a(2,3)~of{ if item//4 <> 0 then 10*item }=
an Array (shape [2,3], 5 items)
[ 1, 1] :  10
[ 1, 2] :  20
[ 1, 3] :  30
[ 2, 2] :  50
[ 2, 3] :  60

/*
If there is more than one argument then each argument is an item as-is.
If some arguments are omitted, then the corresponding item in the initialized array remains non-assigned.
*/
ooRexx[sh]> a(2,3)~of(1,,3,,5,)=
an Array (shape [2,3], 3 items)
[ 1, 1] :  1
[ 1, 3] :  3
[ 2, 2] :  5

/*
reshape

APL R←X⍴Y (Rho)
args : new dimension(s)
*/
ooRexx[sh]> a(5)~of{ 2*item }=
[ 2, 4, 6, 8, 10]
ooRexx[sh]> a(5)~of{ 2*item }~reshape(3,3)=
an Array (shape [3,3], 9 items)
[ 1, 1] :  2
[ 1, 2] :  4
[ 1, 3] :  6
[ 2, 1] :  8
[ 2, 2] :  10
[ 2, 3] :  2
[ 3, 1] :  4
[ 3, 2] :  6
[ 3, 3] :  8

/*
each

APL R←,Y (Ravel)
Y may be any array. R is a vector of the elements of Y taken in row-major order.
inverse of reshape, which turns any data into a vector whose length is the product
of the shape vector (the dimensions) of the operand array
*/
ooRexx[sh]> a(1,2,3)~of{index}=
an Array (shape [1,2,3], 6 items)
[ 1, 1, 1] : [ 1, 1, 1]
[ 1, 1, 2] : [ 1, 1, 2]
[ 1, 1, 3] : [ 1, 1, 3]
[ 1, 2, 1] : [ 1, 2, 1]
[ 1, 2, 2] : [ 1, 2, 2]
[ 1, 2, 3] : [ 1, 2, 3]
ooRexx[sh]> a(1,2,3)~of{index}~each=
[[ 1, 1, 1],[ 1, 1, 2],[ 1, 1, 3],[ 1, 2, 1],[ 1, 2, 2],[ 1, 2, 3]]

/*
depth

APL R←≡Y (Equal Underbar)
Depth (≡) indicates the degree of nesting within an array.
It returns a non-negative integer which defines the maximum number of levels
of structure to be penetrated in order to get to a simple scalar where simple means non-nested.
The depth of an array is 1 greater than that of its most deeply nested item.

Returns "infinity" when the array is self-referencing.
*/
ooRexx[sh]> 1~depth=
 0
ooRexx[sh]> v(1)~depth=
 1
ooRexx[sh]> v(v(1))~depth=
 2
ooRexx[sh]> v=v(1); v~append(v); v~depth=;
(The positive infinity)

/*
enclose

APL R←⊂Y (Left Shoe)
If Y is a simple scalar, R is the simple scalar unchanged.
Otherwise, R has a depth whose magnitude is one greater than the magnitude of the depth of Y.
*/
ooRexx[sh]> e=1~enclose
ooRexx[sh]> e=
 1
ooRexx[sh]> e~depth=
 0
ooRexx[sh]> e=v(1)~enclose~enclose
ooRexx[sh]> e=
<<[ 1]>>
ooRexx[sh]> e~depth=
 3

/*
disclose

APL R←⊃Y (Right Shoe)
Disclose is the inverse of Enclose.
*/
ooRexx[sh]> e=v(1)~enclose~enclose
ooRexx[sh]> e=
<<[ 1]>>
ooRexx[sh]> e=e~disclose
ooRexx[sh]> e=
<[ 1]>
ooRexx[sh]> e~depth=
 2
ooRexx[sh]> e=e~disclose
ooRexx[sh]> e=
[ 1]
ooRexx[sh]> e~depth=
 1

/*
Indexing a vector
It is possible to extract several items in a single operation, and in any order.
An item can be selected more than once.
*/
ooRexx[sh]> vector = (10,20,30,40,50)
ooRexx[sh]> vector~indexer(3)=
[ 30]
ooRexx[sh]> vector~indexer(3,3)=
[ 30, 30]
ooRexx[sh]> 'LE CHAT'~eachc~indexer(7,5,2,3,4,6,7)~tostring("c")=
'THE CAT'

/*
The index may be an array of any shape: scalar, vector, matrix, or an array of higher rank.
When a vector is indexed by an array, the result has exactly the same shape as the index
array, as if each item of the index had been replaced by the item it designates:
*/
ooRexx[sh]> index = a(3,5)~of(5,5,4,4,3,3,2,2,1,1)
ooRexx[sh]> index=
an Array (shape [3,5], 15 items)
[ 1, 1] :  5
[ 1, 2] :  5
[ 1, 3] :  4
[ 1, 4] :  4
[ 1, 5] :  3
[ 2, 1] :  3
[ 2, 2] :  2
[ 2, 3] :  2
[ 2, 4] :  1
[ 2, 5] :  1
[ 3, 1] :  5
[ 3, 2] :  5
[ 3, 3] :  4
[ 3, 4] :  4
[ 3, 5] :  3
ooRexx[sh]> vector = (10,20,30,40,50)
ooRexx[sh]> vector~indexer(index)=
an Array (shape [3,5], 15 items)
[ 1, 1] :  50
[ 1, 2] :  50
[ 1, 3] :  40
[ 1, 4] :  40
[ 1, 5] :  30
[ 2, 1] :  30
[ 2, 2] :  20
[ 2, 3] :  20
[ 2, 4] :  10
[ 2, 5] :  10
[ 3, 1] :  50
[ 3, 2] :  50
[ 3, 3] :  40
[ 3, 4] :  40
[ 3, 5] :  30

/*
End of demonstration.
*/