45

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
    }
}
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Vlad Otrocol
  • 2,952
  • 7
  • 33
  • 55
  • 3
    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? – Bergi Jan 09 '19 at 19:21

10 Answers10

54

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...

J S
  • 1,068
  • 6
  • 7
31

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.

Shidersz
  • 16,846
  • 2
  • 23
  • 48
7

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)
}
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
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
}
AkshayBandivadekar
  • 839
  • 10
  • 18
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
}
Matt H
  • 1,795
  • 1
  • 7
  • 8
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

Thomas Skubicki
  • 536
  • 4
  • 12
1

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.`);
}
Luiz Felipe
  • 869
  • 12
  • 21
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');
    }
}
Maksym Dudyk
  • 1,082
  • 14
  • 16
  • 4
    This would have a runtime of n factorial. – Gabriel Garrett Feb 02 '21 at 18:16
  • 2
    @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. – General Grievance Jan 05 '23 at 14:04
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);
General Grievance
  • 4,555
  • 31
  • 31
  • 45
  • 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! https://stackoverflow.com/help/how-to-answer – pyeR_biz Jul 25 '21 at 06:47
  • The point of this is to check for this while still inside the loop. This answer totally misses that. – General Grievance Jan 05 '23 at 13:45
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
  }
}
ani627
  • 5,578
  • 8
  • 39
  • 45