Powered by QM on a Linux server
Help and Support

KnowledgeBase 00044: Multivalue Functions

Last updated: 27 Dec 2018
Applies to: All versions
Top level index       Full Index Search Tips
Previous article     Next article

The QMBasic language includes a powerful set of functions that operate on multivalued data, repeating some operation for each dynamic array element. These functions allow developers to construct simple solutions to apparently complex problems.

The functions described here are of most use in dictionary I-type expressions but can also be used in programs.

A Simple Example

If we have two dynamic arrays, delimited by value marks

   A      4 vm 6 vm 1 
   B      2 vm 3 vm 5 
QM and several other multivalue implementations allow us to perform arithmetic operations such as adding A and B
   A+B    6 vm 9 vm 6 
where the addition operator has worked on each value pair in turn. Some systems provide this functionality with a function named ADDS()

The concatenation operator (: or CAT) does not work in this way. If we have

   A      P vm Q vm R 
   B      1 vm 2 vm 3 
   C = A : B 
does exactly what we have asked, concatenating the two strings, giving
   P vm Q vm R1 vm 2 vm 3 
What we probably wanted was
   P1 vm Q2 vm R3 
and we can achieve this with the CATS() function.

The SPLICE() function is similar but inserts a single valued separator between the items in each pair

   SPLICE(A,'**',B)   P**1 vm Q**2 vm R**3 

There are many such functions and, with just a few exceptions, their names are formed by adding an S to the equivalent single valued operator or function name, effectively pluralising it. Some work on two dynamic arrays, combining corresponding elements (ADDS, SUBS, MULS, DIVS, CATS, etc). Others apply some operation to each element of a single dynamic array. For example, the OCONVS() function can be used to convert each element of a multivalued list of internal form dates to external form.

Multivalued Relational Operators

The multivalued relational operators (EQS, NES, LTS, LES, GTS, GES) perform a comparison of each element in a pair of dynamic arrays, returning a new dynamic array of the same structure with each element set to 1 or 0 according to the result of the comparison. For example, if we have

   A         4 vm 6 vm 1 
   B         2 vm 3 vm 5 
we could use GTS(A, B) to determine which element is greater in each pair.
   GTS(A,B)  1 vm 1 vm 0 

The true power of these functions only becomes apparent when they are used in combination. We could, for example, use

to determine how many elements of A are greater than B.

Multivalued Conditional Operations

One of the most powerful multivalue functions is IFS() which takes a multivalued list of true/false values and two other dynamic arrays. It then builds a new dynamic array in which the true/false list is used to determine which of the other dynamic arrays is used to form the new value.

   A                  4 vm 6 vm 1 
   B                  2 vm 3 vm 5 
   GTS(A,B)           1 vm 1 vm 0 
   IFS(GTS(A,B),A,B)  4 vm 6 vm 5 
This construct has returned a dynamic array formed from the greater value in each pair.

But What If...

Returning to the simple case of adding two dynamic arrays, what will happen if one has fewer values than the other?

   A      4 vm 6 vm 1 
   B      2 vm 3 
The language defines that the missing item is treated as zero, resulting in
   A+B    6 vm 9 vm 1 
except if it is the divisor in a division operator when it is treated as one.

There are times when what we want to do is to carry forward the last value to substitute for the missing value. We can do this with the REUSE() function.

   A+REUSE(B)  6 vm 9 vm 4 
The REUSE() function simply keeps using the last value until the expression is completely resolved. If we do not know which of the two lists has fewest items, we can even do
   C = REUSE(A) + REUSE(B) 
The most obvious case of needing REUSE() is when one of the items to be processed is single valued. We could, for example, add 20% tax to a multivalued list of prices with
   VALUE = PRICE * REUSE(1.2) 
Simply writing
   VALUE = PRICE * 1.2 
would not work because, as explained above, the right hand side of the multiplication would be taken as zero for the second and subsequent values in PRICE.

A More Complex Example

Imagine we have a sales processing system with an order history file in which field BRANCH contains the single valued branch number at which an order was placed. Field ITEMS contains a multivalued list of items, each formed from a product number and size code separated by an asterisk. A sample record might be

   Branch  Items 
   15986   6379*12 
We want to display the part description alongside each item. These are stored in a separate stock file which is keyed by the branch and product number, separated by a hyphen. We can form the stock file id using
This could then be used in a TRANS() function to retrieve the product descriptions.
   Branch  Items..  Prod......  Description 
   15986   6379*12  15986-6379  Coat, ladies 
           9824*14  15986-9824  Jacket, mens, black weatherproof 
           2537*9   15986-2537  Boots, mens, hiking 
           2732*3   15986-2732  Boots, child 

Related Articles

00094: Dictionary I-Type Records

Please tell us if this article was helpful
Very     Slightly     Not at all
Email (optional)