Reputation: 3190
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
}
}
Upvotes: 54
Views: 72294
Reputation: 44413
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
}
}
Upvotes: 0
Reputation: 6057
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
}
}
Upvotes: 0
Reputation: 43
const chain = ['ABC', 'BCA', 'CBA'];
let findOut;
for (const lastIter of chain) {
findOut = lastIter; //Last iteration value stored in each iteration.
}
console.log(findOut);
Upvotes: 0
Reputation: 840
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
}
Upvotes: 5
Reputation: 997
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.`);
}
Upvotes: 2
Reputation: 17190
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
.
Upvotes: 35
Reputation: 1163
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');
}
}
Upvotes: 0
Reputation: 1198
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...
Upvotes: 65
Reputation: 637
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
Upvotes: 1
Reputation: 1971
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
}
Upvotes: 0