How to determine the last element of a list in a foreach?

7

Given any list, how do I know if foreach is in the last element?

There are a few ways to do this, the most I can see is to save the last element and check if the current element is the same, but in that way it is necessary to check every loop , as in example below:

var last = list.Last();

foreach(var element in list)
{
    if(element == last)
    {
       //is last
    }
}

Is this the best form of performance?

    
asked by anonymous 30.06.2016 / 16:07

2 answers

10

There are some cases where using the Last method can end up causing an iteration throughout the collection, for example, when the collection is the result of a Linq query. This would cause the collection to be iterated twice . Which, of course, you'll want to avoid - especially if you're working with large collections.

As you may already know, foreach itself has nothing that can help you with this. The solution is to find some workaround.

1. Use a for

This is the first one I would consider using

for(int i; i < list.Count; i++)
{
    if(i == list.Count - 1)
    {
    }
}

2. Using a counter variable within the loop

There is also the option to "cache" the size of the list and use a counter variable (I do not see advantages in this approach compared to the use of for )

var index = 0;
var count = list.Count; //ou Count() - você sabe
foreach (var item in list)
{
    if(++index == count)
    {
    }
}

3. Using the method IndexOf

foreach (var item in list)   
{   
     if (list.IndexOf(item) == list.Count - 1) 
     {
     }
}

In particular, I would discourage you from using this approach because the IndexOf method looks for an element in the collection through a loop , ie, in the main loop, another iteration will be done in the IndexOf method.

You can confirm this by viewing the source code of the method IndexOf of List<T> and that of the IndexOf method of class Array

    
30.06.2016 / 16:17
4

I would not go this way.

As jbueno said this is a case where for might be a better idea, so just compare the index with the Count() or Length of the (possibly curly) list.

You can use the same technique within foreach , but you would have to have the index variable to compare with the total of items (minus 1 to indicate the last number). If it is to have this variable, why not make a for ? Something like this:

var count = list.Length;

foreach(var element in list) {
    if (--count > 0) {
        //is last
    }
}

In some cases you can use some option with foreach . It could store the value of the last item and compare it with the current one. But you have to ensure the uniqueness of the values in the whole list. Risky.

The foreach is suitable when you want to iterate over the list more evenly, in cases like this it is not so suitable. But it depends on each case.

If you can use another form (it does not make sense), I found a solution by unlinking what foreach does :

using (var enumerator = .GetEnumerator()) {
    var last = !enumerator.MoveNext();
    T current;
    while (!last) {
        current = enumerator.Current;
        last = !enumerator.MoveNext();
        if (last) {
            //is last
        }       
    }
}

I do not really like this solution, and it can not be used in all cases, but you can use LINQ :

elements.ForEach((element, info) => {
    if (info.IsLast) {
        //is last
    }
});

You can have other creative solutions, variations of these, but in the end changes little, you have to do what is most appropriate for the case. You can not attach to a shape, use whatever is best in the concrete case.

    
30.06.2016 / 16:20