We have a form that we can log BP readings that patients recorded at home. We want to know what the average BP is so I have 7 values for systolic and 7 values for diastolic. Most of the time there will be 7 values so the code will run smoothly. However, I need it to adjust when there may only be 4 or 5 or fewer than 7 values and accurately average the numbers. Is there a way to adjust the code so it will automatically adjust the number it is dividing by? Below is the code I am currently using.
{fn calcavesys()
{local a = ((val(DOCUMENT.SYSBP1)+val(DOCUMENT.SYSBP2)+val(DOCUMENT.SYSBP3)+val(DOCUMENT.SYSBP4)+val(DOCUMENT.SYSBP5)+val(DOCUMENT.SYSBP6)+val(DOCUMENT.SYSBP7))/7)
DOCUMENT.SYSTOTAL = str(a)
return (val(DOCUMENT.SYSTOTAL))
}}
{fn calcavedia()
{local b = ((val(DOCUMENT.DIABP1)+val(DOCUMENT.DIABP2)+val(DOCUMENT.DIABP3)+val(DOCUMENT.DIABP4)+val(DOCUMENT.DIABP5)+val(DOCUMENT.DIABP6)+val(DOCUMENT.DIABP7))/7)
DOCUMENT.DIATOTAL = str(b)
return (val(DOCUMENT.DIATOTAL))
}}
Thank you,
Rebecca
Rebecca,
there are several ways to do this, but the most efficient would be to set up a for loop to calculate the average. See below.
{fn calcavesys()
{
local i = 1
local total = 0
local count = 0
local average
for i=1, i <=7, i=i+1
do
if (eval("DOCUMENT.SYSBP" + str(i)) <> "") then
total = total + eval("val(DOCUMENT.SYSBP" + str(i)))
count = count + 1
else
endif
endfor
average = total/count
return average
}}
You can use the same logic to get the average of diastolic values. You can take advantage of the "eval" function in MEL so long as you use a consistent naming convention with your document variables (i.e. consistent prefix followed by a sequential number) which it appears you have done.
I'm happy to assist you with this if you would like. You are right down the street from us. 🙂
Greg
This is what we are using, I hope it helps:
{fn calcavesys()
{local a = ((val(DOCUMENT.SYSBP1)+val(DOCUMENT.SYSBP2)+val(DOCUMENT.SYSBP3)+val(DOCUMENT.SYSBP4)+val(DOCUMENT.SYSBP5)+val(DOCUMENT.SYSBP6)+val(DOCUMENT.SYSBP7))/
( If DOCUMENT.SYSBP1 <> "" then 1 else 0 endif
+ If DOCUMENT.SYSBP2 <> "" then 1 else 0 endif + If DOCUMENT.SYSBP3 <> "" then 1 else 0 endif + If DOCUMENT.SYSBP4 <> "" then 1 else 0 endif + If DOCUMENT.SYSBP5 <> "" then 1 else 0 endif + If DOCUMENT.SYSBP6 <> "" then 1 else 0 endif + If DOCUMENT.SYSBP7 <> "" then 1 else 0 endif)
)
DOCUMENT.SYSTOTAL = str(a)
return (val(DOCUMENT.SYSTOTAL))
}}
{fn calcavedia()
{local b = ((val(DOCUMENT.DIABP1)+val(DOCUMENT.DIABP2)+val(DOCUMENT.DIABP3)+val(DOCUMENT.DIABP4)+val(DOCUMENT.DIABP5)+val(DOCUMENT.DIABP6)+val(DOCUMENT.DIABP7))/
( If DOCUMENT.DIA BP1 <> "" then 1 else 0 endif
+ If DOCUMENT. DIA BP2 <> "" then 1 else 0 endif + If DOCUMENT. DIA BP3 <> "" then 1 else 0 endif + If DOCUMENT. DIA BP4 <> "" then 1 else 0 endif + If DOCUMENT. DIA BP5 <> "" then 1 else 0 endif + If DOCUMENT. DIA BP6 <> "" then 1 else 0 endif + If DOCUMENT. DIA BP7 <> "" then 1 else 0 endif7)
)
DOCUMENT.DIATOTAL = str(b)
return (val(DOCUMENT.DIATOTAL))
}}
Thank you so much Greg! That is exactly what I was looking for. I am still a novice on using some of this MEL and I knew there had to be a solution to this. I will work on this.
Thank you for offering to help too!! I may need to pick your brain and it's nice to work with someone close by!
Thanks,
Rebecca
Any time!
Hi Rebecca,
As it was mentioned before, there are many ways to solve a problem. However, there's no need to use two separate functions that are basically doing the same thing. In this case, you only need a single function which will calculate the average of an unspecified number of parameters ("getAVG" is the name I've chosen for this function). The code you have, as it is right now, is restricted to seven variables; nothing more, nothing less. What would happen if tomorrow you have to create a form that requires ten or five variables? You'd have to rewrite the function, change the variable names, and change the number of variables. To solve this, a better approach would be to remove the document variables in the function and have them be declared in a watcher or a button. In that way, the function can be reused as many times as you need on as many forms as you want. By using getnargs() and getarg(), you can process as many variables as you need in a single function.
getnargs - Gets the number of arguments entered (7)
getarg - Gets the argument identified by the index you enter (running a FOR loop will loop through all of them)
//Function declaration
{
fn getAVG(){
local result = ""
local i = ""
local num = 0
local den = 0
//The for loop is gonna skip blank variables
for i = 1, i <= getnargs(), i = i + 1 do
if str(getarg(i)) <> "" then
num = num + val(str(getarg(i)))
den = den + 1
else "" endif
endfor
result = num/den
return result
}
}
Another precaution I took is the use of str() and val(str()). You can enter any type of argument (string or number) and the code won't crash because you are always converting them to the type you need.
*The reason why I'm wrapping val() around str() is because numbers cause val() to crash, but strings don't. Also, Str() can take both types of variables.
It's also worth mentioning that a key technique used by experienced developers is re-utilization. The code you create has to be reusable. By having only local variables, the above function can work on any form (not only those with BP variables).
The following code shows how to use the getAVG function.
//Code in button or watcher
DOCUMENT.SYSTOTAL = getAVG(DOCUMENT.SYSBP1,DOCUMENT.SYSBP2,DOCUMENT.SYSBP3,DOCUMENT.SYSBP4,DOCUMENT.SYSBP5,DOCUMENT.SYSBP6,DOCUMENT.SYSBP7...)
DOCUMENT.DIATOTAL = getAVG(DOCUMENT.DIABP1,DOCUMENT.DIABP2,DOCUMENT.DIABP3,DOCUMENT.DIABP4,DOCUMENT.DIABP5,DOCUMENT.DIABP6,DOCUMENT.DIABP7...)
Not only can you use getAVG for calculating the average of seven BP values, you could also use it to get the average of 1 or even 200 variables.
If you've got any questions, please let me know. I'm always happy to help.
Best,
Tomas Vazquez
Senior Developer – Team Lead
One Boston Place, Suite #2600 - Boston, MA 02108
D: (617) 390-8928 O: (617) 848-4488 F: (617) 996-1241
www.optumus.com – @optumus.com">cmcdonald@optumus.com