2
votes

On Lucee 4.5.1.003 I have this function where LineArray is an array of LineItem objects.

public function getLineItemDetailsById(required numeric id){
    this.LineArray.each(function(i){
        if(i.Id == id){
            return i;
        }
    });
}

The function returns null even if there is a match. If I add a var to hold the found object, the var is returned.

public function getLineItemDetailsById(required numeric id){
    var found = '';
    this.LineArray.each(function(i){
        if(i.Id == id){
            found = i;
            //return i;
        }
    });
    return found;
}

Am I doing something wrong expecting array.each to return i or am I misunderstanding how array.each works?

Edit: To be clear, the second function does return the found object.

3

3 Answers

2
votes

You need to look slightly closer at the code in your first example:

public function getLineItemDetailsById(required numeric id){ // first function
    this.LineArray.each(function(i){ // second function
        if(i.Id == id){
            return i; // return for second function
        }
    });
    // no return from first function
}

I have annotated it slightly to demonstrate your problem. getLineItemDetailsById() "returns null" because you simply aren't returning anything from it. So if you have:

result = getLineItemDetailsById(1);

then getLineItemDetailsById() is not returning anything, so result ends up being null.

So that's the problem you're seeing.

Furthermore, you don't want to be using each() within that function: one would only use each() when you definitely want to iterate over the entire array. In your case it seems like you want to exit as soon as you find a match for id.

In which case you want something like this:

public function getLineItemDetailsById(required numeric id){
    var matchedElement = null; 
    this.LineArray.some(function(element){
        if(element.Id == id){
            matchedElement = element;
            return true;
        }
    });
    return matchedElement;
}

One uses some() when one wants to iterate over an array only until some criteria is matched. Here I'm leveraging this to set the matchedElement when the exit criteria is met.

0
votes

If ID is always expected to exist use:

public function getLineItemDetailsById(required numeric id){
    return this.LineArray.Find(function(i){return i.ID==id);});
}
0
votes
.each     loops through the entire array and returns void
.reduce   returns a single value after looping through all elements
.some     allows an exit sooner than each

(See docs for more methods)

for(i in this.lineArray)if(i.id is id) return i; ... avoids some overhead

Although a better way, in most cases, is to populate this.lineStruct from this.lineArray, ahead of time.

this.lineStruct={}; 
this.lineArray.each(function(i){this.lineStruct[i.id]=i;});
function getLineById(id) 
{   return this.lineStruct.keyexists(id)?this.lineStruct[id]:null;   }