Question
· Sep 13, 2017

is there a reverse version of $listNext ?

Cache 2016.2.1

the system offers $LISTNEXT as a way of looping  in $LISTs and the documentation says this is much more efficeint than writing

for i=1:1:$LISTLENGTH(myList) { set value = $LIST (myList,i) }

I want to walk backwards in the list,

is there a $LISTPREVIOUS or do I have to use the followng syntax to achie

 for i=1:-1:$LISTLENGTH(myList)

kevin

Discussion (4)0
Log in or sign up to continue

Not, we don't have $listprevious. And I can say why.

$listbuild format quite simple where each element of $listbuild is solid. It has header and data, where in the header we have the length of data. So, to get next element, we just have to read header and ptr used to set position where header begins. 

But when you want to read the previous element, you can't know how long this previous value, and you can't find this right place, you still have to read from the beginning.

So, only one way to do it:

for i=$listlength(myList):-1:1 

If you're really interested in efficiency, one option might be put the list into a local array with $ListNext and then iterate over the array in reverse (either with a decrementing counter in a for loop, or using $order(array(sub),-1)). For example, rather than:

For i=$ListLength(tInputList):-1:1 {
    Set tValue = $ListGet(tInputList,i)
    // Do something with tValue
}

You could use something like the following (which accounts for null values in the $ListBuild list by skipping that index in the integer-subscripted array):

Kill tArray
Set tPointer = 0
While $ListNext(tInputList,tPointer,tValue) {
    If $Data(tValue) {
        Set tArray($i(tArray)) = tValue
    } Else {
        Set tArray = tArray + 1
    }
}

Set tKey = ""
For i=$Get(tArray):-1:1 {
    If $Data(tArray(i),tValue) {
        // Do something with tValue
    }
}

For "large enough" lists (the threshold for this depends on the length of the list elements), the second approach will be faster. (In testing, this performs better than putting the reversal of the original $ListBuild list into another $ListBuild list.)

More generally speaking: if you have a list that you only append to the end of (rather than needing to insert/shift elements randomly in the middle of it), and will need to iterate over it in reverse, a local array with integer subscripts is a better choice of data structure than a $ListBuild list.

In addition to the above.

Fill the array tArray can be charged a method %ListOfDataTypes:BuildValueArray().
But I still prefer the next option (unless you count every tick of CPU :) ):

list=##class(%ListOfDataTypes).%New()
list.InsertList(tInputList)
 
; method #1
key="" {value=list.GetPrevious(.key)while (key'="")
 
; method #2 (better way)
key=list.Size:-1:1 value=list.GetAt(key)