I was challenged to make a 2D array in MEL. I'm not sure it's possible, but while working on it, I found something I can't figure out.
Basically, I have a 3x3 grid of edit fields. I have made an array for each horizontal row and each vertical column, six in total. I have also made a final array that holds the six previous arrays.
It looks like this:
local fourteenArray= ""
local thirteenArray = ""
local twelveArray = ""
local fastArray = ""
local pcbArray = ""
local aclArray = ""
local matrixArray = ""
fourteenArray = array(DOCUMENT.FAST_1, " AAAAAAAAAAAA ", DOCUMENT.PCB_1, DOCUMENT.ACL_1)
thirteenArray = array(DOCUMENT.FAST_2, " BBBBBBBBB ", DOCUMENT.PCB_2, DOCUMENT.ACL_2)
twelveArray = array(DOCUMENT.FAST_3, " CCCCCCCCC ", DOCUMENT.PCB_3, DOCUMENT.ACL_3)
fastArray = array(DOCUMENT.FAST_1, " DDDDDDD ", DOCUMENT.FAST_2, DOCUMENT.FAST_3)
pcbArray = array(DOCUMENT.PCB_1, " EEEEEEE ", DOCUMENT.PCB_2, DOCUMENT.PCB_3)
aclArray = array(DOCUMENT.ACL_1, " FFFFFFFFF ", DOCUMENT.ACL_2, DOCUMENT.ACL_3)
matrixArray = array(fourteenArray, thirteenArray, twelveArray, fastArray, pcbArray, aclArray)
DOCUMENT.TEST = matrixArray</code>
matrixArray is inside a document variable, DOCUMENT.TEST, displayed in an edit text. Here's where it gets weird. If I run the code as it appears up above (I tied it to a button so it fires manually), the six arrays do appear in the seventh array, but they repeat. I added a letter between two of the elements of each array to test this. The final code block runs an array, then loops back to the beginning of the list of arrays to start again. So in the end, you get this (I'm only using the letters to better illustrate what happens): "A, A, B, A, B, C, A, B, C, D, A, B, C, D, E, A, B, C, D, E, F"
However, if I put a hard return between each array in the matrixArray, the arrays don't repeat, and we get:
"A,
B,
C,
D,
E,
F"
If I leave out one of the HRETs, only the section missing the HRET repeats.
"A,
B,
C,
D,
E,
E, F,
F"
This is really weird and I just can't put my finger on why this is happening.
Also, has anyone had any luck making a 2Dmatrix in MEL?
Multi dimensional arrays are possible. I have seen them used with getfield() to parse delimited output from mel. I could not find any examples of it so I wrote my own just to make sure I was not getting it confused with something else.
Here is a quick mel function I wrote which takes the contents of two arrays and makes them the first two elements of a multidimentional array. You access the elements with arrayname[1][1] being the first element of the first array and [1][2] being the second element of the first array and so on.
{
fn arraytest(){
local aTest = array("A","B","C")
local aTest2 = array("D","E","F")
local mdaTest = array(aTest, aTest2)
local output = ""
for x = 1, x <= size(mdaTest), x = x + 1 do
for y = 1, y <= size(mdaTest[x]), y = y + 1 do
output = output + "mdaTest[" + x + "][" + y + "] = " + mdaTest[x][y] + HRET
endfor
endfor
return output
}
arraytest()
}
The output of the above function looks like this:
mdaTest[1][1] = A
mdaTest[1][2] = B
mdaTest[1][3] = C
mdaTest[2][1] = D
mdaTest[2][2] = E
mdaTest[2][3] = F
I tested the above code in a new test handout.
Try using a for loop to print out the array like I did to see what is in each element. It is possible your issue is in the display of the array within your form.
I seriously cannot thank you enough. I was getting hung up on what was going on with the arrays before I even started a for loop. By adding in your example loops, it straightened everything out. I was then able to add a third array and some variables, and now I have a single statement that populates 7 different OBS terms with 98 unique values, backdated appropriately. Now all I have to do is figure out how to add additional variables in order to average the values of filled in fields in each column, but I that shouldn't be too hard.
Here's what I ended up with, for future reference/users. I've trimmed it down, but left in two of my DOCUMENT variable arrays as examples and my OBSArray.
{
!fn arrayTest() {
local a14 = ""
local a13 = ""
local matrixArray = ""
local OBSArray = ""
local output = ""
local dateSubCount = 15
local yCount = 1
/*Arrays*/
a14 = array(DOCUMENT.FAST_1, DOCUMENT.PCB_1, DOCUMENT.ACL_1, DOCUMENT.PCL_1, DOCUMENT.ACD_1, DOCUMENT.PCD_1, DOCUMENT.QHS_1)
a13 = array(DOCUMENT.FAST_2, DOCUMENT.PCB_2, DOCUMENT.ACL_2, DOCUMENT.PCL_2, DOCUMENT.ACD_2, DOCUMENT.PCD_2, DOCUMENT.QHS_2)
OBSArray = array("BG FASTING", "BG PC 1H BRK", "BG AC LUNCH", "BG PC 1H LUN", "BG AC DINNER", "BG PC 1H DIN", "BG BEDTIME")
matrixArray = array(a14, a13, a12, a11, a10, a09, a08, a07, a06, a05, a04, a03, a02, a01)
for x = 1, x <= size(matrixArray), x = x + 1 do
dateSubCount = dateSubCount - 1
for y = 1, y <= yCount, y = y + 1 do
/*yCount increases by 1 on each loop. It has to increase after the OBS construction, otherwise we always miss the first entry in OBSArray. This lets us cycle through OBS terms. str(matrixArray[x][y]) finds the value of the field at the x,y coordinates. str(dateSubCount) subtracts 1 on each loop to backdate the value to the correct date.*/
OBSNOW(OBSArray[yCount], str(matrixArray[x][y]), SUBTRACTDATES(str(._TODAYSDATE), "", "", str(dateSubCount)))
/*This if statement resets yCount at the end of each row, otherwise it counts beyond 7 and breaks the loops. */
if yCount = size(OBSArray) then
yCount = 1
else
yCount = yCount + 1
endif
endfor
endfor
}
}
I do not think you need the ycount variable. If I am reading your code correctly, ycount should always be the same as y when your OBSNOW is run. Your comment says that it will count beyond 7 but it cant since size(OBSArray) = 7 and you say it has to be less than or equal to that in order to run your for loop. You should be able to change your for loop to:
for y = 1, y <= size(OBSArray), y = y + 1 do
OBSNOW(OBSArray[y]....
The variable Y will automatically reset at the end of every row to 1.
You're right... I get so focused on fixing individual problems that I sometimes lose the bigger picture. I removed yCount and things seem to be working so far! I think I almost have the averaging squared away. When I do, I'll be posting that here for future reference.
So as it turns out, I had my x and y flipped. I needed the arrays to be columns instead of rows so I could more easily add and average the totals. I did that and got this:
{
!fn calcAverages() {
local fastArray = ""
local PCBArray = ""
local ACLArray = ""
local PCLArray = ""
local ACDArray = ""
local PCDArray = ""
local QHSArray = ""
local matrixArray = ""
local OBSArray = ""
local avgOBSArray = ""
local dateSubCount = 14
local avgSum = 0
local fieldCount = 0
local finalAvg = 0
/*Arrays*/
/*These arrays work in columns instead of in rows. This makes it easier to add and average the totals of each column.*/
fastArray = array(DOCUMENT.FAST_1, DOCUMENT.FAST_2, DOCUMENT.FAST_3, DOCUMENT.FAST_4, DOCUMENT.FAST_5, DOCUMENT.FAST_6, DOCUMENT.FAST_7, DOCUMENT.FAST_8, DOCUMENT.FAST_9, DOCUMENT.FAST_10, DOCUMENT.FAST_11, DOCUMENT.FAST_12, DOCUMENT.FAST_13, DOCUMENT.FAST_14)
PCBArray = array(DOCUMENT.PCB_1, DOCUMENT.PCB_2, DOCUMENT.PCB_3, DOCUMENT.PCB_4, DOCUMENT.PCB_5, DOCUMENT.PCB_6, DOCUMENT.PCB_7, DOCUMENT.PCB_8, DOCUMENT.PCB_9, DOCUMENT.PCB_10, DOCUMENT.PCB_11, DOCUMENT.PCB_12, DOCUMENT.PCB_13, DOCUMENT.PCB_14)
ACLArray = array(DOCUMENT.ACL_1, DOCUMENT.ACL_2, DOCUMENT.ACL_3, DOCUMENT.ACL_4, DOCUMENT.ACL_5, DOCUMENT.ACL_6, DOCUMENT.ACL_7, DOCUMENT.ACL_8, DOCUMENT.ACL_9, DOCUMENT.ACL_10, DOCUMENT.ACL_11, DOCUMENT.ACL_12, DOCUMENT.ACL_13, DOCUMENT.ACL_14)
PCLArray = array(DOCUMENT.PCL_1, DOCUMENT.PCL_2, DOCUMENT.PCL_3, DOCUMENT.PCL_4, DOCUMENT.PCL_5, DOCUMENT.PCL_6, DOCUMENT.PCL_7, DOCUMENT.PCL_8, DOCUMENT.PCL_9, DOCUMENT.PCL_10, DOCUMENT.PCL_11, DOCUMENT.PCL_12, DOCUMENT.PCL_13, DOCUMENT.PCL_14)
ACDArray = array(DOCUMENT.ACD_1, DOCUMENT.ACD_2, DOCUMENT.ACD_3, DOCUMENT.ACD_4, DOCUMENT.ACD_5, DOCUMENT.ACD_6, DOCUMENT.ACD_7, DOCUMENT.ACD_8, DOCUMENT.ACD_9, DOCUMENT.ACD_10, DOCUMENT.ACD_11, DOCUMENT.ACD_12, DOCUMENT.ACD_13, DOCUMENT.ACD_14)
PCDArray = array(DOCUMENT.PCD_1, DOCUMENT.PCD_2, DOCUMENT.PCD_3, DOCUMENT.PCD_4, DOCUMENT.PCD_5, DOCUMENT.PCD_6, DOCUMENT.PCD_7, DOCUMENT.PCD_8, DOCUMENT.PCD_9, DOCUMENT.PCD_10, DOCUMENT.PCD_11, DOCUMENT.PCD_12, DOCUMENT.PCD_13, DOCUMENT.PCD_14)
QHSArray = array(DOCUMENT.QHS_1, DOCUMENT.QHS_2, DOCUMENT.QHS_3, DOCUMENT.QHS_4, DOCUMENT.QHS_5, DOCUMENT.QHS_6, DOCUMENT.QHS_7, DOCUMENT.QHS_8, DOCUMENT.QHS_9, DOCUMENT.QHS_10, DOCUMENT.QHS_11, DOCUMENT.QHS_12, DOCUMENT.QHS_13, DOCUMENT.QHS_14)
OBSArray = array("BG FASTING", "BG PC 1H BRK", "BG AC LUNCH", "BG PC 1H LUN", "BG AC DINNER", "BG PC 1H DIN", "BG BEDTIME")
avgOBSArray = array("BG FASTING A", "BG POSTBKFTA", "BG PRE-LNCHA", "BG POSTLNCHA", "BG PRE-DINRA", "BG POSTDINRA", "BG BEDTIME A")
matrixArray = array(fastArray, PCBArray, ACLArray, PCLArray, ACDArray, PCDArray, QHSArray)
/*Everything in the x loop (before and after the y loop) works on every column. I do all the count resets in the x loop because they only need to count up or down in each iteration of the y loop.*/
for x = 1, x <= size(matrixArray), x = x + 1 do
dateSubCount = 14
/*Everything in the y loop works for each field in the column*/
for y = 1, y <= 14, y = y + 1 do
/*OBSArray[y] keeps track of the position in the OBSArray array by using the value of x. str(matrixArray[x][y]) finds the value of the field at the x,y coordinates. str(dateSubCount) subtracts 1 on each loop to backdate the value to the correct date.*/
OBSNOW(OBSArray[x], str(matrixArray[x][y]), SUBTRACTDATES(str(._TODAYSDATE), "", "", str(dateSubCount)))
dateSubCount = dateSubCount - 1
/*avgSum is a total of every field in a column*/
avgSum = avgSum + matrixArray[x][y]
/*This checks to see if a field is filled in. If it is, fieldCount is incremented by 1. This will end up being the number avgSum is averaged by.*/
if matrixArray[x][y] "" then
fieldCount = fieldCount + 1
else
fieldCount = fieldCount
endif
endfor
/*We do this math and resets after the y loop is complete because we need the totals for that column. We reset avgSum and fieldCount here because they need to enter the next iteration of the x loop back at 0 to begin the process again.*/
if avgSum 0 and
fieldCount 0 then
finalAvg = avgSum/fieldCount
OBSNOW(avgOBSArray[x], str(round(finalAvg)))
else
""
endif
avgSum = 0
fieldCount = 0
endfor
}
}
Thanks again for your help. This was really fun to puzzle out.