Let’s say we have a function that makes expensive calculation and an array of source values for which we do the calculation. We want to get a first return value of the function that is not null and return it.
function expensiveFunction(params) {...}
// this is how it can be achieved using ordinary for loop
let paramsCollection = ["params1", "params2" /*, ...*/];
let result;
for (let i=0; i<paramsCollection.length; i++) {
result = expensiveFunction(paramsCollection[i]);
if (result) {
break;
}
}
I’d like to do it using Array methods.
Array.find
will only return the element for which function returns something.
Array.map
will run expensive calculations for all elements even if first one was ok.
Array.reduce
can do the job, but it will iterate over an array anyway – even if it doesn’t call the expensiveFunction
it feels bad..
let paramsCollection = ["params1", "params2" /*, ...*/];
let result = paramsCollection.reduce((acc, cur) => acc ? acc : expensiveFunction(cur), null);
Any idea how to make it this way but w/out drawbacks from above examples?
3
Answers
You can write your own
mapFind
based onArray.prototype.find
:You have a contradiction in your question:
if (result)
and "not null" are not equivalent. I assumendif (result)
. If you actually mean "not null", you can replaceif (temp)
withif (temp !== null)
andreturn temp;
withreturn temp !== null;
.ECMAScript 2025 will include iterator helpers, which are being rolled out now, so if you have that available (like in current versions of Edge, Chrome, …), then this would do it:
Note that:
.values()
returns an iterator (not an array)..map()
and.find()
are not array methods, but (new) iterator methods.find
on that item, we get a result produced byexpensiveFunction
.map
method will only consume values as they are needed by the iterator’sfind
method. Once thefind
method has found the value that is truthy,map
will not consume any more values.NB: If you only want to skip
null
values (but not other falsy values), then the.find
call back could bex => x !== null
.Example:
I’m sure I’ve missed something in the nuance of the question, but why can’t you just use findIndex:
findIndex
runs a function, returning the first index that returns a non-falsey value.