Arrays

Use this section to showcase your programming examples. Or to ask members for programming suggestions
Post Reply
User avatar
Zenerdiode
Posts: 43
Joined: Wed Jan 04, 2023 12:45 am
Location: Newcastle, England

Arrays

Post by Zenerdiode »

I’m missing having either a two dimensional array, or a way to dynamically address an array in OPL. For example, I know I can do:

Code: Select all

TEST:
LOCAL array1$(10,5),array2$(10,5),i%,j%
i%=1
array1$(i%)=2 :REM etc.
but how could I do:

Code: Select all

TEST:
LOCAL array1$(10,5),array2$(10,5),i%,j%
i%=1
j%=2
array(j%)$(i%)=2 :REM etc.
If you get what I mean…?
Christopher. - Check out my TRAP message, it’s not difficult to decode and is sometimes uttered under the breath when said message appears… :|
User avatar
Martin
Global Admin
Posts: 216
Joined: Mon Jan 02, 2023 5:18 pm

Array work-a-round

Post by Martin »

Hi Chris

You are correct there is no multi-dimensional arrays... OPL was created mainly as a file handling programming language. With that in mind I have in the past used the file handling capabilities as a way round the issue. It's long winded but something like...

Code: Select all

TEST:
LOCAL r%,v%,counter%,varible$(7)

REM CM/XP procedure use XTRAN on LZ

REM create test array
IF EXIST("A:TSTARY")
 DELETE "A:TSTARY"
ENDIF
CREATE "A:TSTARY",A,no%,value1$,value2$ :REM could have more value$'s
counter%=1

REM dimension test array file with 'blank' data (9 records)
DO
 A.no%=counter%
 A.value1$="-"   :REM would normally be empty strings ""
 A.value2$="-"   :REM but here use "-" to display later
 APPEND
 counter%=counter%+1
UNTIL counter%>9 :REM for his exercise limit no. of records to 9

REM Place values in the test array
WHILE varible$<>"Q"
 CLS
 REM Endless loop only way out is "Q"
 PRINT "String (Q=quit)" :INPUT varible$
 IF varible$="Q" : GOTO OUTPUT:: :ENDIF
 REM    1234567890123456
 PRINT "recrd 1 to 9 "; :INPUT r%
 PRINT "value 1 or 2 "; :INPUT v%
 
 FIRST
 DO
  IF A.no%=r% :REM no assignment will take place if r%>counter% OR v%>2
   IF v%=1 :A.value1$=varible$ :ENDIF
   IF v%=2 :A.value2$=varible$ :ENDIF
   UPDATE : BREAK
  ENDIF
  NEXT
 UNTIL EOF
ENDWH

OUTPUT::
REM Display values
FIRST
DO
 CLS
 REM    1234567890123456
 PRINT "Record No. ";A.no%
 PRINT LEFT$(A.value1$,7);CHR$(9);LEFT$(A.value2$,7)
 PAUSE -100
 KEY
 NEXT
UNTIL EOF
PRINT "all done.."
GET
I used something like it in my land surveying data logger, I remember I needed the 'array' to be in order so had to create a sort routine that I could call each time data was added or updated to sort the file back into order.. Note in that case make A.no% into A.no$ see page 2 of the Database Files Hints and Tips (here).

Always sincere
Martin
User avatar
Zenerdiode
Posts: 43
Joined: Wed Jan 04, 2023 12:45 am
Location: Newcastle, England

Re: Arrays

Post by Zenerdiode »

Thanks Martin, they say two great minds think alike, I had already tried to use temporary files to act as 2D arrays - but they were taking three seconds to open and using eight, the waiting time is excessive.

I have to rethink, I may just use many LOCALs and address them absolutely, but with that comes many IF statements.

Programming is our crossword or sudoku puzzles :D
Christopher. - Check out my TRAP message, it’s not difficult to decode and is sometimes uttered under the breath when said message appears… :|
Lostgallifreyan
Posts: 83
Joined: Thu Jan 12, 2023 8:25 pm

Re: Arrays

Post by Lostgallifreyan »

You know how arrays are constructed, so consider using the address like pointer arithmetic and access in C code. (Bear in mind that strings have their own weird un-C-like rules but can still be used in a similar way, it's just a fixed-length buffer you can do what you want with.)

My 'Bytes' program that allows placing arbitrary binary strings into locations various, while more than you need, suggests that a small bit of machine code to handle the read and write of an array by direct addressing is feasible, and likely fast too. You can do it OPL but there may be a tax on speed. PEEKB and PEEKW of ADDR(A%) act like BYTE and WORD casts respectively. Floating Point arrays would be harder to handle but there may well be a machine service that can do it, if called by ASM.

A variable is allocated space that your procedures own for their lifetime, and globals can be reached by sub-procedures, so you're free to access them any way you can so long as the result doesn't compromise OPL's ability to see them as originally intended when it needs to.
MartinP
Posts: 46
Joined: Wed Jan 04, 2023 7:51 pm

Re: Arrays

Post by MartinP »

Zenerdiode,
I'm not that sure about what you mean by "dynamically address an array" but maybe you could use a flattened array? i.e. a 2d array stored in a 1d array, then just use a formula for the indices.
So for a 5x2 array, you'd use a 10 element 1d array, then for the indices use the formula: x%+(y%-1)*xx% where x% is the x index, and y% is the y index and xx% is the width of the array in the x direction (5 in this case).
This works for string or numeric arrays. You need to use the index formula every time you index the array, but this could be put into a function i:(x%,y%) to make the code look neater (although this will slow it down a bit).
See example below, which prints out a 2d array of words, most of which are "LO", but one says "HI". The width parameter xx% is made global so that it doesn't need to be passed to the index function every time.
If x% and y% are also made global, you wouldn't need to pass them either, but I prefer the look of it this way.
Martin P.

Code: Select all

array2d:
local x%,y%,yy%,array$(10,2)
global xx%
xx%=5 :yy%=2
x%=3 :y%=2
array$(i:(x%,y%))="HI"
x%=1 :y%=1
do
 do
  if array$(i:(x%,y%))=""
   array$(i:(x%,y%))="LO"
  endif
  print array$(i:(x%,y%)),
  x%=x%+1
 until x%=xx%+1
 print
 x%=1
 y%=y%+1
until y%=yy%+1
get

Code: Select all

i:(x%,y%)
RETURN x%+(y%-1)*xx%
Post Reply