7

I have an array with defined and null values inside, like so :

var arr = [
  {...},
  null,
  null,
  {...},
  null
];

Is there any way for me to get the index of the last non-null element from this array? And I mean without having to loop through it entirely.

Zenoo
  • 12,670
  • 4
  • 45
  • 69

5 Answers5

8

You could use a while loop and iterate from the end.

var array = [{ foo: 0 }, null, null, { bar: 42 }, null],
    index = array.length;
    
while (index-- && !array[index]);

console.log(index);
console.log(array[index]);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Already thought of that, I was asking for a way without a loop. – Zenoo May 22 '17 at 12:07
  • 1
    actually, you need a loop or some kind of loop like the build in arraymethods, but they loop only from the beginning, and `reduceRight` has no early exit. – Nina Scholz May 22 '17 at 12:11
  • So I guess there is no way of doing this without a loop then ... I was thinking there could be a .index for non-null elements. Thanks for trying anyway. – Zenoo May 22 '17 at 12:26
4

Filter the non-null get the value of last one, if you need the index get the index from the value. But requires the values to be unique.

// Last non-null value
const lastNonNull = arr.filter(x => x).pop();
// Index of last non-null
const indexOfLastNonNull = arr.indexOf(lastNonNull);

--Edit(1)

You may want to use reduce method of arrays, but before run reverse to make sure the sequence is from last to first. reduce works pretty fine, the first initial value is null then we check for result which is the first initial value so we pass on cur which is the first element of array, if it is truthy we return idx which is the index of array, if not we return null which will become the result in the next loop.

arr.reduce((result, cur, idx) => (result ? result : (cur ? idx : null)), null)

--Edit(2)

Or you may reverse the array and run indexOf like this:

arr.indexOf(null);

For reversing once you run arr.reverse() it'll reverse the content of array. No need to return anything.

PRAISER
  • 793
  • 7
  • 15
  • I don't really get how your .filter() filters out the null elements. Can you elaborate a bit please? – Zenoo May 22 '17 at 12:10
  • Sure, to check if a variable is `null` or `undefined` you simple check it with a truthy and in JS it's like this `if (variableX) ...` in the sample I wrote it's the same case, the conditional is basically the variable itself, so if `x` is `null` or `undefined` it returns false, and won't be included in the return. Remember the fat arrow functions `=>` is for this case to return the expression without writing the whole function. – PRAISER May 22 '17 at 12:12
  • To elaborate a bit more the filter fat arrow is equivalent of `filter( function(x) { return x; } )`. – PRAISER May 22 '17 at 12:15
  • `filter` visits *every* element of an array. – Nina Scholz May 22 '17 at 12:15
  • Thanks, I get it now. But as said, going through every element of my array would not be a good idea, it can contain up to 10 000 entries. – Zenoo May 22 '17 at 12:23
  • It's quiet fine to run a loop by JSEngine rather a for loop in my opinion. But at the end there is no way to find the right value without a loop. Good luck – PRAISER May 22 '17 at 12:33
0

Try this:

array.length - array.slice(0).reverse().findIndex(function (el) { return el }) - 1;
berniecc
  • 401
  • 4
  • 6
0
const reverse = arr => {
    let cpy = [...arr];
    cpy.reverse();
    return cpy;
};

const nonNullIndex = arr => {
    let res = arr.length - 1 - reverse(arr).findIndex(e => e !== null)

    return res === arr.length ? -1 : res;
};

This should work. The reverse function returns an array, as Array.prototype.reverse reverses it in-place, not returning anything.

The nonNullIndex function returns the last index where it isn't null. Since it reverses the array, you must subtract the index found from the length of the array. The subtraction of one is used so that it returns the right value (since arrays are indexed at 0).

If the result is equal to the length (meaning that findIndex returned -1), it returns -1, meaning there are no null values in the array. Otherwise, it returns the result.

Milesman34
  • 177
  • 1
  • 6
0

You can use the map function to iterate through the array, check the condition and return the index, then take the maximum index:

Math.max.apply(null, arr.map(function (v, i) { return v !== null && i; });

or

Math.max(...arr.map((v, i) => v !== null && i));
iROOT
  • 1