I am new in programming with natural, coming from a JAVA/Node background. I am currently going through all the tutorial material I can find on the SAG website but the specific task I am trying to accomplish is not further shown in the official DOCS nor the video series.
Basically, I want to perform a simple task which is removing a dynamic arrays value at a specific index given via the INPUT statement.
In other languages this would look something like this
array := array.removeAtIndex(#input)
I could not find any way of doing this the “natural” way. So far I wrote a small program but I am stuck at the DELETE or ALTER part of the array.
DEFINE DATA LOCAL
1 #ARRAY (A45/1:*)
1 #ITEM_COUNT (I4)
1 #LOOP-INDEX (I4)
1 #DEL_INDEX (I2)
1 #VALUE (A45)
END-DEFINE
/* ADD 3 TESTVALUES TO #ARRAY
FOR #LOOP-INDEX =1 TO 3
PERFORM ADD_ITEM
END-FOR
/*REMOVE AT INDEX
PERFORM DELETE_AT_INDEX
DEFINE SUBROUTINE ADD_ITEM
#ITEM_COUNT := *OCC(#ARRAY(*))
WRITE 'ITEM COUNT BEFORE ADD_ITEM:' #ITEM_COUNT 'LBOUND' *LBOUND(#ARRAY) 'UBOUND' *UBOUND(#ARRAY) /
#ITEM_COUNT := #ITEM_COUNT+1
EXPAND ARRAY #ARRAY TO (1:#ITEM_COUNT)
COMPRESS 'NEWVALUE' #LOOP-INDEX TO #ARRAY(#ITEM_COUNT)
END-SUBROUTINE
DEFINE SUBROUTINE DELETE_AT_INDEX
WRITE '****************ARRAY CONTENT***********************'//
FOR #LOOP-INDEX = 1 TO *UBOUND(#ARRAY)
WRITE 'INDEX=' #LOOP-INDEX(AD=L) 'VALUE=' #ARRAY(#LOOP-INDEX)
END-FOR
INPUT 'INDEX TO BE DELETED:' #DEL_INDEX
/******************************************************************
/*TO-DO REDUCE ARRAY (REMOVE AT IDNEX #DEL_INDEX) DISPLAY NEW ARRAY
/******************************************************************
END-SUBROUTINE
END
I would very much appreciate if someone could help me out here or at least push me into the right direction.
Their “array” is actually a linked list ; you remove an item by attaching the links from it’s neighbours to each other to cut it out (which is fast)
They copy the entire array to a new array without the removed item (which is perceived as an OK spend of computing power and memory, because these are languages that aren’t from the 1970s)
The docs for REDUCE read like Natural changes the value of the top index and deallocates the memory at the end of the array, which means to remove an item at index N you have to copy all items above index N to one index lower, THEN do a REDUCE.
It might be easier and faster to just blank items you don’t want to process and then write loops that only process non-blank items.
Thank you for your quick response. I will try that. I made the mistake thinking I can treat an dynamic array like a List of other languages like Java. Thank you very much.
DEFINE DATA LOCAL
1 #ARRAY (A45/1:*)
1 #ITEM_COUNT (I4)
1 #LOOP-INDEX (I4)
1 #DEL_INDEX (I2)
1 #VALUE (A45)
1 #TOP_INDEX (I2)
END-DEFINE
/* ADD TESTVALUES TO #ARRAY
#TOP_INDEX := 5
EXPAND ARRAY #ARRAY TO (1:#TOP_INDEX)
FOR #LOOP-INDEX =1 TO #TOP_INDEX
PERFORM ADD_ITEM
END-FOR
/*REMOVE AT INDEX
PERFORM DELETE_AT_INDEX
DEFINE SUBROUTINE ADD_ITEM
#ITEM_COUNT := *OCC(#ARRAY(*))
WRITE 'ITEM COUNT BEFORE ADD_ITEM:' #ITEM_COUNT 'LBOUND' *LBOUND(#ARRAY) 'UBOUND' *UBOUND(#ARRAY) /
#ITEM_COUNT := #ITEM_COUNT+1
COMPRESS 'NEWVALUE' #LOOP-INDEX TO #ARRAY(#LOOP-INDEX)
END-SUBROUTINE
DEFINE SUBROUTINE DELETE_AT_INDEX
WRITE '****************ARRAY CONTENT***********************'//
FOR #LOOP-INDEX = 1 TO *UBOUND(#ARRAY)
WRITE 'INDEX=' #LOOP-INDEX(AD=L) 'VALUE=' #ARRAY(#LOOP-INDEX)
END-FOR
INPUT 'INDEX TO BE DELETED:' #DEL_INDEX
#TOP_INDEX := *UBOUND(#ARRAY)
if #DEL_INDEX < #TOP_INDEX /* if eq, then just erase top index, nothing to shift.
#ARRAY(#DEL_INDEX:#TOP_INDEX -1) := #ARRAY(#DEL_INDEX+1:#TOP_INDEX)
end-if
#TOP_INDEX := #TOP_INDEX - 1
RESIZE ARRAY #ARRAY TO (1:#TOP_INDEX)
/******************************************************************
/*TO-DO REDUCE ARRAY (REMOVE AT IDNEX #DEL_INDEX) DISPLAY NEW ARRAY
/******************************************************************
FOR #LOOP-INDEX = 1 TO *UBOUND(#ARRAY)
WRITE 'INDEX=' #LOOP-INDEX(AD=L) 'VALUE=' #ARRAY(#LOOP-INDEX)
END-FOR
END-SUBROUTINE
END
note that I try to minimize the EXPAND/REDUCE/RESIZE operations as an EXPAND to add one occurrence (for example) means a new array is allocated with room for one more array entry and values copied from original array to new one. In a large loop, that is a lot of CPU. If you know the size of the array in advance, then just allocate that with one EXPAND/RESIZE statement. If you don’t know it, use a reasonably large estimate, then only allocate more room if that is used up (and allocate larger chunks that just 1 if it makes sense). If needed, once the array is loaded, use REDUCE/RESIZE to free up unused elements.