Length of Array in progress? - progress-4gl

Given two arrays, ( for example 1,2,3,4,5 and 2,3,1,0). Find which number of first array is not present in the second array. How can i get Length of Arrays in progress 4gl ?

If the object in question is an ARRAY, rather than a LIST, you use the EXTENT() function to determine the number of elements. Using arrays:
define variable a1 as integer no-undo extent 5 initial [ 1, 2, 3, 4, 5 ].
define variable a2 as integer no-undo extent 4 initial [ 2, 3, 1, 0 ].
define variable i as integer no-undo.
define variable j as integer no-undo.
define variable ok as logical no-undo.
do i = 1 to extent( a1 ):
ok = no.
do j = 1 to extent( a2 ):
if a1[i] = a2[j] then ok = yes.
end.
if ok = no then message a1[i] "is not in a2".
end.

To have the length of a list (number of items of the list), you can use NUM-ENTRIES() function.
To know if an item is present in a list, you can use LOOKUP() function.
So for your example, you can do something like this:
DEFINE VARIABLE wclist1 AS CHARACTER NO-UNDO INITIAL "1,2,3,4,5".
DEFINE VARIABLE wclist2 AS CHARACTER NO-UNDO INITIAL "2,3,1,0".
DEFINE VARIABLE wc-list-no-present AS CHARACTER NO-UNDO.
DEFINE VARIABLE wi-cpt AS INTEGER NO-UNDO.
/* For each items of list1 */
DO wi-cpt = 1 TO NUM-ENTRIES(wclist1, ","):
/* Test if the item is in list 2 */
IF LOOKUP(ENTRY(wi-cpt, wclist1, ","), wclist2, ",") = 0
THEN
wc-list-no-present = wc-list-no-present + "," + ENTRY(wi-cpt, wclist1, ",").
END.
/* TRIM is to remove the first "," */
DISPLAY TRIM(wc-list-no-present, ",").

def var a as int extent 5 initial [1,2,3,4,5] no-undo.
def var b as int extent 4 initial [2,3,1,0] no-undo.
def var i as int no-undo.
def var j as int no-undo.
loop:
repeat i = 1 to extent(a):
repeat j = 1 to extent(b):
if a[i] = b[j]
then next loop.
end.
Display a[i] "not in b array" format "x(20)".
end.

Related

How to get common words from two different sentences by using ENTRY function in progress4gl?

How to get common words from two different sentences by using ENTRY function in progress4gl?
define variable a1 as character no-undo initial "hi dude do".
define variable a2 as character no-undo initial "hi man it".
define variable cnta as character.
define variable cntb as character.
define variable cntc as character.
define variable i as integer.
define variable j as integer.
do i = 1 to 3:
entry (i,a1,"").
do j = 1 to 3:
entry (j,a2,"").
end.
end.
/* assign cntc = cnta matches cntb . */
define variable a1 as character no-undo initial "hi dude do".
define variable a2 as character no-undo initial "hi man it".
define variable common as character no-undo.
define variable cc as integer no-undo.
define variable ii as integer no-undo.
define variable jj as integer no-undo.
define variable n1 as integer no-undo.
define variable n2 as integer no-undo.
n1 = num-entries( a1 ).
n2 = num-entries( a2 ).
do ii = 1 to n1:
do jj = 1 to n2:
if entry ( ii, a1, " ") = entry( jj, a2, " " ) then
do:
cc = cc + 1.
common = common + " " + entry( ii, a1, " " ).
end.
end.
end.
display trim( cc ) common.
Notes:
The TRIM() function is just to clean up the "common" string so it doesn't have an extra space.
For performance reasons it is good to get in the habit of obtaining NUM-ENTRIES() outside the loop rather than with every iteration of the loop. It doesn't make much difference for small strings but for large strings it can have quite an impact.
1./*if i need to get the n number of words in two sentences from the user at the run time , how to compare and the get the common words.
the following code compares and displays only first letter of the two sentence.
*/
define variable a1 as character no-undo.
define variable a2 as character no-undo.
define variable common as character no-undo.
define variable a1 as character FORMAT "x(64)" no-undo /* initial "hi d do" */.
define variable a2 as character FORMAT "x(64)" no-undo /* initial "hi d it" */.
define variable common as character FORMAT "x(64)" no-undo.
define variable c1 as character FORMAT "x(64)" no-undo.
define variable x as character FORMAT "x(64)" no-undo.
define variable y as character FORMAT "x(64)" no-undo.
define variable cc as integer no-undo initial 0.
define variable ii as integer no-undo.
define variable jj as integer no-undo.
define variable n1 as integer no-undo.
define variable n2 as integer no-undo.
set a1.
n1 = num-entries( a1,"" ).
set a2.
n2 = num-entries( a2,"" ).
do ii = 1 to n1:
do jj = 1 to n2:
if entry ( ii,a1, " ") matches entry( jj,a2, " " ) then
do:
common = entry( ii, a1, " " ).
display common .
end.
end.
end.

Using frames in progress 4gl

Can anyone help me understand how to display the following pattern using a Progress 4gl frame:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5.
I have tried like this:
DEFINE VARIABLE a AS INTEGER NO-UNDO.
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DO
a =1 TO 5 WITH FRAME f:
DO
b = 1 TO a WITH FRAME f:
DISPLAY a SPACE SKIP.
PAUSE.
END.
END.
/* while displaying the answer is overwritten, how do I display the answer side by side? */
If you were sending your output to a file you could do it like this:
define variable a as integer no-undo.
define variable b as integer no-undo.
output to "output.txt".
do a = 1 to 5:
do b = 1 to a:
put b.
end.
put skip.
end.
output close.
Using DISPLAY and FRAME is not like text files or printers. When you create a frame and DISPLAY "A" in it you are defining a single position where the variable will be displayed.
Every time that you DISPLAY A the value will be placed in the same position.
You can make it a DOWN frame and move to a new line with each iteration of the outer loop but you will still only have one position per line.
define variable a as integer no-undo.
define variable b as integer no-undo.
do a = 1 to 5 with frame f:
do b = 1 to a:
display b with frame f.
end.
down with frame f.
end.
To have multiple positions you need multiple variables or an array or you can build a string (doydoy44's solution). Here is an example with an array:
define variable a as integer no-undo.
define variable b as integer no-undo.
define variable c as integer no-undo extent 5 format ">>>>".
do a = 1 to 5 with frame f:
do b = 1 to a:
c[b] = b.
end.
display c with frame f.
down with frame f.
end
I'm not sur to understand what is the problem.
May be this can help you:
DEFINE VARIABLE a AS INTEGER NO-UNDO.
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DEFINE VARIABLE woutput AS CHARACTER NO-UNDO.
DO
a =1 TO 5 WITH FRAME f:
woutput = "".
DO
b = 1 TO a WITH FRAME f:
woutput = woutput + " " + string(b).
END.
DISPLAY TRIM(woutput) SKIP .
PAUSE.
END.
The behaviour you are talking about is what I call a down frame. ABL creates a frame automatically for any output, and if you are displaying a series of records from a table, it knows to make that frame a down frame, for example:
for each customer no-lock:
display customer.
end.
But in your example you aren't using for each. To get the down frame behaviour you are going to have to make it happen yourself.
Here is the simplest code that will give you that:
def var v-i as int no-undo.
do v-i = 1 to 10 with down:
display v-i.
down.
end.
It's actually clearer what is going on, though, if you spell things out a bit further. Let's define a named frame, make it a down frame, and then use it:
def var v-i as int no-undo.
def frame f-x
v-i
with down.
do v-i = 1 to 10:
display v-i with frame f-x.
down with frame f-x.
end.
It's almost always worth defining a frame if you are outputting something, I find.
define variable a as int no-undo.
define variable b as int no-undo.
define variable res as char no-undo.
update a.
b = 1.
repeat while(b <= a):
res = res + " " + string (b).
b = b + 1.
disp res format "x(20)".
end.

is it possible to use MaximumFuntion within an Entry Funciton in Progress 4gl

I am new to progress and I am trying to figure out how to get this working. My task is to Get a list of integer values from user as semi colon separated and message the highest and lowest value on that list. Till now I have used an entry function to help me get just the integers entered by the user one after another. like so
repeat I = 1 to totalEntries:
m = entry (I, Userinput, ";").
display m.
end.
After this I would like to find out the maximum value of all the entries. how can I do this since maximum function accepts more than one value for comparison.
There is no built in function to give a maximum or minimum number from given list of numbers. You need to write your own logic as in most of the programming languages. Here is an example:
DEF VAR i AS INT.
DEF VAR nlist AS CHAR INIT "1;2;7;3;6;9".
DEF VAR imin AS INT.
DEF VAR imax AS INT.
imin = INTEGER(ENTRY (1, nlist, ";")).
imax = INTEGER(ENTRY (1, nlist, ";")).
REPEAT i = 2 TO NUM-ENTRIES(nlist, ";"):
IF INTEGER(ENTRY(i, nlist, ";")) > imax THEN
imax = INTEGER(ENTRY(i, nlist, ";")).
IF INTEGER(ENTRY(i, nlist, ";")) < imin THEN
imin = INTEGER(ENTRY(i, nlist, ";")).
END.
MESSAGE imax.
MESSAGE imin.
As Austin sad, there is no built-in function in Progress to give a maximum or minimum number from a list.
In your comment, you've mentioned that MAXIMUM(1,2,3) worked. Yes, it works, but you have to figure that you're passing three parameters to the function, not a list of numbers inside a single CHAR variable.
To solve your problem you can use the solution given by Austin or you can use two functions that receive a CHAR variable with semi colon separated values and return maximum or minimum values.
Here is an example, based on your code.
FUNCTION iMax RETURNS INTEGER
( INPUT pData AS CHAR ):
DEF VAR iOutput AS INT NO-UNDO.
DEF VAR iCount AS INT NO-UNDO.
iOutput = ?.
DO iCount = 1 TO NUM-ENTRIES(pData,';'):
IF iOutput = ? THEN DO:
iOutput = INT(ENTRY(iCount,pData,';')).
NEXT.
END.
iOutput = MAX(iOutput,INT(ENTRY(iCount,pData,';'))).
END.
RETURN iOutput.
END FUNCTION.
FUNCTION iMin RETURNS INTEGER
( INPUT pData AS CHAR ):
DEF VAR iOutput AS INT NO-UNDO.
DEF VAR iCount AS INT NO-UNDO.
iOutput = ?.
DO iCount = 1 TO NUM-ENTRIES(pData,';'):
IF iOutput = ? THEN DO:
iOutput = INT(ENTRY(iCount,pData,';')).
NEXT.
END.
iOutput = MIN(iOutput,INT(ENTRY(iCount,pData,';'))).
END.
RETURN iOutput.
END FUNCTION.
/****************/
Define variable NumberEntry as character view-as fill-in no-undo.
Define variable UsersInput as character no-undo.
Define variable i as integer no-undo.
Define variable totalEntries as integer no-undo.
Define variable m as character no-undo.
Define variable n as character no-undo.
Define button bFind.
Define frame main numberEntry label "Enter numbers separated by semi colon" skip
bFind label "Find Max and Min" with side-labels. /*Trigger for button*/
On choose of bFind in frame main do: /*Retrieve the users input*/
Usersinput = (numberEntry:screen-value). /*to find out how many characters the user has enterd.*/ totalEntries = num-entries(UsersInput,';'). Display totalentries. /*Logic to extract Users input values one by one.*/
Repeat i = 1 to totalEntries: M = entry(i, UsersInput, ";").
Display m.
End. /*Logic to find the maximum element. */ .....
MESSAGE 'MAXIMUM :' iMax(UsersInput) SKIP
'MINIMUM :' iMin(UsersInput)
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.
VIEW FRAME main.
ENABLE ALL WITH FRAME main.
WAIT-FOR CHOOSE OF bfind.
You can call iMax() or iMin() and get MAX or MIN values from Progress MAXIMUM and MINIMUM function using a CHAR list of INTEGER values separated by semi colons without need to make a full code block to do the comparision and get the information for each situation that presents necessary.
Hope it helps.

setting a label after define

I have a display statement and I only display one of the values if a logical is true. How can I NOT display the label of the column (ie. blank)
def var one as char label "one" no-undo.
def var two as char label "two" no-undo.
def var three as char label "three" no-undo.
def var four as char label "four" no-undo.
def var logic as logi no-undo init no.
display
one
two
three
four when logic
with stream-io width 80.
define variable one as character no-undo initial "xyz".
define variable two as character no-undo initial "123".
define variable f as handle no-undo.
define variable h as handle no-undo.
form
one two
with frame a
.
f = frame a:handle.
if two = "" then
do:
h = f:first-child.
walk_tree: do while valid-handle( h ):
if h:name = "two" then
do:
h:label = "x".
leave walk_tree.
end.
h = h:next-sibling.
end.
end.
display
one two
with frame a
.
Easy Way:
def var a as char label "One" init "AAA".
def var b as char label "Two" init "BBB".
def var c as char label "three" init "CCC".
def var logic as logical init false.
form a b c with frame a no-underline.
if logic = false then c:label in frame a = "".
display a b c when logic with frame a.

Copy character values from character array variable to character (string) variable

this is my issue
define varibale MyArray as character extent 40 no-undo.
define variable Mychara as character no-undo.
Mychara = "hai this is checking how to copy values"
Now i want to copy this string to my "MyArray". So that it should be as follows
MyArray[1]=h ,MyArray[2]=a ,MyArray[3]=i ,MyArray[4]="" ,MyArray[5]=t ,MyArray[6]=h
and so on...
So how to do it?
Given your code-example, this should do the trick:
define variable MyArr as character EXTENT 40 no-undo.
define variable Mychara as character no-undo.
Mychara = "hai this is checking how to copy values".
DEF VAR i AS INT NO-UNDO.
DO i = 1 TO 40:
MyArr[i] = SUBSTRING(MyChara,i,1).
END.
A caveat though: this means that you have to know the (maximum) size of your String beforehand, to define the array size appropriately.
little bit dynamically ;)
define variable MyArr as character EXTENT no-undo.
define variable Mychara as character no-undo.
DEF VAR i AS INT NO-UNDO.
Mychara = "hai this is checking how to copy values".
EXTENT (MyArr) = LENGTH (Mychara).
DO i = 1 TO EXTENT (MyArr):
MyArr[i] = SUBSTRING(MyChara,i,1).
END.
define var l_mychara as integer no-undo.
define variable MyArray as character format "x(5)" extent 40 no-undo.
define variable Mychara as character format "x(5)" no-undo.
def var i as int init 1.
Mychara = "hai this is checking how to copy values".
assign l_mychara = length(Mychara).
do while i <= l_mychara.
assign myarray[i] = substring(mychara,i,1).
if myarray[i] = "" then assign myarray[i] = "blank".
i = i + 1.
end.
disp Myarray .