Detect last iteration in FOR OF loop in ES6 javascript
Asked Answered
B

11

54

There are multiple ways of finding out the last iteration of a for and for...in loop. But how do I find the last iteration in a for...of loop. I could not find that in the documentation.

for (item of array) {
    if (detect_last_iteration_here) {
        do_not_do_something
    }
}
Britten answered 9/1, 2019 at 19:10 Comment(1)
This is not really possible - an iterator could be infinite. You only know whether it is the last element after checking for the next. What exactly do you need this for?Celestinecelestite
E
63

One approach is using Array.prototype.entries():

for (const [i, value] of arr.entries()) {
    if (i === arr.length - 1) {
        // do your thing
    }
}

Another way is keeping a count outside the loop like Shidersz suggested. I don't think you want to check indexOf(item) though because that poses a problem if the last item is duplicated somewhere else in the array...

Extraterritoriality answered 9/1, 2019 at 19:31 Comment(0)
D
35

One possible way is to initialize a counter outside the loop, and decrement it on every iteration:

const data = [1, 2, 3];
let iterations = data.length;

for (item of data)
{
    if (!--iterations)
        console.log(item + " => This is the last iteration...");
    else
        console.log(item);
}
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Note that !--iterations is evaluated as !(--iterations) and the expression will be true when iterations=1.

Defective answered 9/1, 2019 at 19:15 Comment(0)
S
8

You could slice the array and omit the last element.

var array = [1, 2, 3],
    item;
    
for (item of array.slice(0, -1)) {
    console.log(item)
}
Suprasegmental answered 9/1, 2019 at 19:18 Comment(2)
OP wants to detect last element, not strip out the last element from the arraySoissons
for the lat item nothing should happen. so it does.Suprasegmental
R
5

With ES6, by calling the entries() method on the array you can do it =>

const array = [1, 2, 3];
for (const [i, v] of array.entries()) {
    //Handled last iteration
    if( i === array.length-1) {
        continue;
    }
    console.log(i, v)// it will print index and value
}
Romina answered 13/11, 2021 at 15:18 Comment(0)
A
2

A more generalized alternative, firmly based in composition principles, is implement another iterator using a generator function. This will, in fact, compose these two iterators.

The new iterator will basically delegate the actual yielding of the values to the original iterator. The difference is that the former will alyaws be “one step ahead” of the latter. By doing so, the new iterator will be capable of verify, for each element, if the iteration has stopped with the next one.

function* withLast(iterable) {
  const iterator = iterable[Symbol.iterator]();
  let curr = iterator.next();
  let next = iterator.next();
  while (!curr.done) {
    yield [next.done, curr.value];
    [curr, next] = [next, iterator.next()];
  }
}

Notice that, in the first iteration, next is called twice. For each of the following iterations, next is always called once, only for the element that corresponds one step ahead of the current iteration.

Learn more about the JavaScript iteration protocols to learn more about that implementation.

A little more concrete example:

function* withLast(iterable) {
  const iterator = iterable[Symbol.iterator]();
  let curr = iterator.next();
  let next = iterator.next();
  while (!curr.done) {
    yield [next.done, curr.value];
    [curr, next] = [next, iterator.next()];
  }
}

const arr = [1, 2, 3];
for (const [isLast, element] of withLast(arr)) {
  console.log(`${element} ${isLast ? 'is' : 'is not'} the last.`);
}

As concepts like index or the actual length of the iterator – the latter which isn't even a thing in some corner cases as infinite iterators – aren't used in this solution, this approach is well suited for any kind of iterator.

Another example:

function* withLast(iterable) {
  const iterator = iterable[Symbol.iterator]();
  let curr = iterator.next();
  let next = iterator.next();
  while (!curr.done) {
    yield [next.done, curr.value];
    [curr, next] = [next, iterator.next()];
  }
}

// Generator function that creates a "generic" iterator:
function* gen() {
  yield 'a';
  yield 'b';
  yield 'c';
}

for (const [isLast, element] of withLast(gen())) {
  console.log(`${element} ${isLast ? 'is' : 'is not'} the last.`);
}
Almund answered 9/9, 2021 at 13:50 Comment(0)
S
1

If you want to change your loop behavior based the specific index, then it's probably a good idea to use an explicit index in your for-loop.

If you simply want to skip out on the last element, you can do something like

for (item of array.slice(0, -1)) {
    //do something for every element except last
}
Stryker answered 9/1, 2019 at 19:21 Comment(0)
B
1

There doesnt seem to be anything the the spec for for..of for this. There seems to be two work-arounds:

If you can, just push a marker to the end of the array and act on that marker, like so:

myArray.push('FIN')
for (el of myArray){
    if (el === 'FIN')
        //ending code
}

Alternatively, you can use the below to get an index you can use in tandem with an Array.length

enter link description here

Boyer answered 9/1, 2019 at 19:31 Comment(0)
J
0

The simpliest way to find the last loop and, let's say, get rid of the last comma insert during iterration is to compare the length of array with the index of its last item.

const arr = ["verb", "noun", "pronoun"];

for (let item of arr) {
    if (arr.length -1 !== arr.indexOf(item)) {
        console.log('With Commas');
    } else {
        console.log('No Commars');
    }
}
Jolynjolynn answered 26/7, 2020 at 16:32 Comment(2)
This would have a runtime of n factorial.Otherness
@GabrielGarrett I think it's actually quadratic, but yes, still not great. The main issue with this answer, though, is that it's incorrect. If there are any duplicate values in the array, it will never detect the last iteration. On the other hand, if lastIndexOf were used, it would still fail if there are duplicates in the array.Gegenschein
D
0
const chain = ['ABC', 'BCA', 'CBA'];
let findOut;
for (const lastIter of chain) {
    findOut = lastIter;       //Last iteration value stored in each iteration. 
} 

console.log(findOut);
Doubtful answered 24/7, 2021 at 14:12 Comment(2)
Thank you for trying to answer, but if the questions already has several answers and your answer does not add anything new to the discussion please remove it! stackoverflow.com/help/how-to-answerValrievalry
The point of this is to check for this while still inside the loop. This answer totally misses that.Gegenschein
P
0

Using the following approach you can find the last iteration in a for...of loop:

let iCount = 0;

for( const obj of arrObjects) {
  iCount = iCount + 1;
  if (iCount < arrObjects.length) {
    // Some code to execute on first to (last - 1) elements
  }
  else {
    // Some code only for the last element
  }
}
Priggish answered 30/5, 2023 at 6:36 Comment(0)
M
0

You could also use Array.prototype.at() with -1
See MDN on Array.prototype.at() here for reference.

Your example would simply look like this:

for (item of array) {
    if (item === array.at(-1)) {
        // do_not_do_something
    }
}
Manet answered 30/10, 2023 at 15:38 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.