Foreach loop, determine qual é a última iteração do loop

233

Eu tenho um foreachloop e preciso executar alguma lógica quando o último item for escolhido List, por exemplo:

 foreach (Item result in Model.Results)
 {
      //if current result is the last item in Model.Results
      //then do something in the code
 }

Posso saber qual loop é o último sem usar loop e contadores?

acidente
fonte
1
Dê uma olhada na minha resposta aqui para obter uma solução que eu postei para uma pergunta relacionada.
Brian Gideon

Respostas:

294

Se você apenas precisar fazer algo com o último elemento (em oposição a algo diferente com o último elemento, o uso do LINQ ajudará aqui:

Item last = Model.Results.Last();
// do something with last

Se você precisar fazer algo diferente com o último elemento, precisará de algo como:

Item last = Model.Results.Last();
foreach (Item result in Model.Results)
{
    // do something with each item
    if (result.Equals(last))
    {
        // do something different with the last item
    }
    else
    {
        // do something different with every item but the last
    }
}

Embora você provavelmente precise escrever um comparador personalizado para garantir que você possa dizer que o item é igual ao item retornado por Last().

Essa abordagem deve ser usada com cautela, pois Lastpode ser necessário percorrer a coleção. Embora isso possa não ser um problema para coleções pequenas, se ficar grande, poderá ter implicações no desempenho. Também falhará se a lista contiver itens duplicados. Nesse caso, algo como isto pode ser mais apropriado:

int totalCount = result.Count();
for (int count = 0; count < totalCount; count++)
{
    Item result = Model.Results[count];

    // do something with each item
    if ((count + 1) == totalCount)
    {
        // do something different with the last item
    }
    else
    {
        // do something different with every item but the last
    }
}
ChrisF
fonte
1
O que eu precisava era: Quando o loop estiver passando por seu último item: foreach (Item result em Model.Results) {if (result == Model.Results.Last ()) {<div> last </div>; } Parece que você praticamente quis dizer a mesma coisa.
acidente
10
O código iterará duas vezes por toda a coleção - ruim se a coleção não for pequena. Veja esta resposta.
Shimmy Weitzhandler
54
Isso realmente não funciona se você tiver duplicatas em sua coleção. Por exemplo, se você estiver trabalhando com uma coleção de seqüências de caracteres e houver duplicatas, o código "diferente do último item" será executado para cada ocorrência do último item da lista.
muttley91
7
Esta resposta é antiga, mas para outras pessoas que olham para essa resposta, você pode obter o último elemento e garantir que não precise percorrer os elementos usando: Item last = Model.Results [Model.Results.Count - 1] A contagem A propriedade de uma lista não requer loop. Se você possui duplicatas em sua lista, basta usar uma variável iteradora em um loop for. Regular velho para loops não são ruins.
Michael Harris
Sugiro a usar var last = Model.Result[Model.Result.Count - 1];para uma mais rápida do que usandoLast()
Tân
184

Que tal um bom loop antiquado para?

for (int i = 0; i < Model.Results.Count; i++) {

     if (i == Model.Results.Count - 1) {
           // this is the last item
     }
}

Ou usando o Linq e o foreach:

foreach (Item result in Model.Results)   
{   
     if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
             // this is the last item
     }
}
Fiona - myaccessible.website
fonte
14
Muitas pessoas pensam demais em um problema simples como este, quando o loop for já é perfeitamente capaz de fazê-lo. : \
Andrew Hoffman
A solução Linq é a minha favorita absoluta! Obrigado por compartilhar
mecograph
Essa é a resposta mais apropriada que a aceita.
Ratul 23/08/19
Nota para quem deseja usar a solução LINQ em uma coleção de cadeias (ou tipos de valor): Geralmente não funcionará porque a comparação == falhará se a última cadeia na lista também aparecer anteriormente na lista. Funcionaria apenas se você estiver trabalhando com uma lista garantida para não ter seqüências de caracteres duplicadas.
Tawab Wakil 06/04
Infelizmente você não pode usar esta solução inteligente, se Model.Resultsfor um IEnumerable. Você pode chamar Count()antes do loop, mas isso pode causar a iteração completa da sequência.
Luca Cremonesi
42

O uso Last()de certos tipos percorrerá toda a coleção!
Significando que, se você fizer uma foreachchamada e fizer um Last()loop duas vezes! o que tenho certeza que você gostaria de evitar em grandes coleções.

Então a solução é usar um do whileloop:

using var enumerator = collection.GetEnumerator();

var last = !enumerator.MoveNext();
T current;

while (!last)
{
  current = enumerator.Current;        

  //process item

  last = !enumerator.MoveNext();        
  if(last)
  {
    //additional processing for last item
  }
}

Portanto, a menos que o tipo de coleção seja do tipo, IList<T>a Last()função irá percorrer todos os elementos da coleção.

Teste

Se sua coleção fornece acesso aleatório (por exemplo, implementos IList<T>), você também pode verificar seu item da seguinte maneira.

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps
Shimmy Weitzhandler
fonte
1
Tem certeza de que o enumerador precisa de uma usingdeclaração? Eu pensei que isso seria necessário apenas se um objeto manipular recursos do sistema operacional, mas não para estruturas de dados gerenciadas.
Crouching Kitten
O IEnumerator não implementa IDisposable, portanto, a linha com o uso com gera um erro de tempo de compilação! +1 para a solução, na maioria das vezes não podemos simplesmente usar a para em vez de foreach, porque vários itens de coleções são calculados em tempo de execução ou a sequência não suporta acesso aleatório.
Saleh
1
O genérico faz.
Shimmy Weitzhandler
40

Como Chris mostra, Linq funcionará; basta usar Last () para obter uma referência à última no enumerável e, desde que você não esteja trabalhando com essa referência, faça seu código normal, mas se você estiver trabalhando com essa referência, faça seu trabalho extra. Sua desvantagem é que sempre haverá complexidade O (N).

Em vez disso, você pode usar Count () (que é O (1) se o IEnumerable também for um ICollection; isso é verdade para a maioria dos IEnumerables internos comuns) e híbrir sua foreach com um contador:

var i=0;
var count = Model.Results.Count();
foreach (Item result in Model.Results)
{
    if (++i == count) //this is the last item
}
KeithS
fonte
22
foreach (var item in objList)
{
  if(objList.LastOrDefault().Equals(item))
  {

  }
}
Gabriel Tiburcio
fonte
Olá, esta é a melhor abordagem até agora! Simples e direto ao ponto. Uma abordagem do programador, uma. Por que não escolhemos e damos a este +1 mais e mais!
Hanny Setiawan
1
O último item deve ser encontrado apenas uma vez ( Promover memorização ) antes do foreachbloco. Como esta: var lastItem = objList.LastOrDeafault();. Em seguida, a partir do interior de foreachloop que você pode verificá-lo desta forma: f (item.Equals(lastItem)) { ... }. Na sua resposta original, a objList.LastOrDefault()iteração seria feita sobre a coleção em cada iteração "foreach" ( complexidade polinomial está envolvida ).
22418 AlexMelw
Resposta ruim. complexidade n ^ 2 em vez de n.
Shimmy Weitzhandler 31/01
11

Como Shimmy apontou, usar Last () pode ser um problema de desempenho, por exemplo, se sua coleção é o resultado ao vivo de uma expressão LINQ. Para evitar várias iterações, você pode usar um método de extensão "ForEach" como este:

var elements = new[] { "A", "B", "C" };
elements.ForEach((element, info) => {
    if (!info.IsLast) {
        Console.WriteLine(element);
    } else {
        Console.WriteLine("Last one: " + element);
    }
});

O método de extensão é parecido com este (como um bônus adicional, ele também informa o índice e se você está vendo o primeiro elemento):

public static class EnumerableExtensions {
    public delegate void ElementAction<in T>(T element, ElementInfo info);

    public static void ForEach<T>(this IEnumerable<T> elements, ElementAction<T> action) {
        using (IEnumerator<T> enumerator = elements.GetEnumerator())
        {
            bool isFirst = true;
            bool hasNext = enumerator.MoveNext();
            int index = 0;
            while (hasNext)
            {
                T current = enumerator.Current;
                hasNext = enumerator.MoveNext();
                action(current, new ElementInfo(index, isFirst, !hasNext));
                isFirst = false;
                index++;
            }
        }
    }

    public struct ElementInfo {
        public ElementInfo(int index, bool isFirst, bool isLast)
            : this() {
            Index = index;
            IsFirst = isFirst;
            IsLast = isLast;
        }

        public int Index { get; private set; }
        public bool IsFirst { get; private set; }
        public bool IsLast { get; private set; }
    }
}
Daniel Wolf
fonte
9

Melhorando ainda mais a resposta de Daniel Wolf, você pode empilhar outra IEnumerablepara evitar várias iterações e lambdas, como:

var elements = new[] { "A", "B", "C" };
foreach (var e in elements.Detailed())
{
    if (!e.IsLast) {
        Console.WriteLine(e.Value);
    } else {
        Console.WriteLine("Last one: " + e.Value);
    }
}

A implementação do método de extensão:

public static class EnumerableExtensions {
    public static IEnumerable<IterationElement<T>> Detailed<T>(this IEnumerable<T> source)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source));

        using (var enumerator = source.GetEnumerator())
        {
            bool isFirst = true;
            bool hasNext = enumerator.MoveNext();
            int index = 0;
            while (hasNext)
            {
                T current = enumerator.Current;
                hasNext = enumerator.MoveNext();
                yield return new IterationElement<T>(index, current, isFirst, !hasNext);
                isFirst = false;
                index++;
            }
        }
    }

    public struct IterationElement<T>
    {
        public int Index { get; }
        public bool IsFirst { get; }
        public bool IsLast { get; }
        public T Value { get; }

        public IterationElement(int index, T value, bool isFirst, bool isLast)
        {
            Index = index;
            IsFirst = isFirst;
            IsLast = isLast;
            Value = value;
        }
    }
}
Fabricio Godoy
fonte
1
A outra resposta não itera a fonte várias vezes; portanto, esse não é um problema que você está corrigindo. Você realmente permitiu o uso de foreach, o que é uma melhoria.
Servy
1
@ Service quero dizer isso. Além da iteração única da resposta original, estou evitando lambdas.
Fabricio Godoy
7

A implementação do iterador não fornece isso. Sua coleção pode ser IListacessível através de um índice em O (1). Nesse caso, você pode usar um forloop normal :

for(int i = 0; i < Model.Results.Count; i++)
{
  if(i == Model.Results.Count - 1) doMagic();
}

Se você conhece a contagem, mas não pode acessar por meio de índices (portanto, o resultado é um ICollection), pode contar-se incrementando um ino foreachcorpo do e comparando-o com o comprimento.

Tudo isso não é perfeitamente elegante. A solução de Chris pode ser a mais bonita que eu já vi até agora.

Matthias Meid
fonte
Ao comparar o desempenho do seu contador na solução foreach idea versus Chris, pergunto-me qual custaria mais - uma única chamada Last () ou a soma de todas as operações de incremento adicionadas. Eu suspeito que seria perto.
TTT
6

Que tal pouca abordagem mais simples.

Item last = null;
foreach (Item result in Model.Results)
{
    // do something with each item

    last = result;
}

//Here Item 'last' contains the last object that came in the last of foreach loop.
DoSomethingOnLastElement(last);
faisal
fonte
2
Não sei por que alguém lhe deu um voto negativo. Isso é perfeitamente aceitável, considerando que você já está executando um foreach e está incorrendo no custo de o (n).
Arviman
2
Apesar de a resposta ser perfeita para descobrir o último item, ela não se adequa à condição do OP " ..., determina qual é a última iteração do loop ". Portanto, não é possível determinar que a última iteração é realmente a última e, portanto, você não pode lidar com isso de maneira diferente ou mesmo ignorá-lo. Essa é a razão pela qual alguém lhe deu um voto negativo. @arviman você estava tão curioso sobre isso.
AlexMelw
1
Você está certo, eu senti muita falta dele @ Andrey-WD. Eu acho que a solução a ser corrigida é chamar "last" uma vez antes do loop (não é possível fazê-lo dentro do loop, pois seria O (N ^ 2) e, em seguida, verifique se a referência corresponde.
arviman
5

A melhor abordagem provavelmente seria apenas executar essa etapa após o loop: por exemplo

foreach(Item result in Model.Results)
{
   //loop logic
}

//Post execution logic

Ou se você precisar fazer algo até o último resultado

foreach(Item result in Model.Results)
{
   //loop logic
}

Item lastItem = Model.Results[Model.Results.Count - 1];

//Execute logic on lastItem here
Dustin Hodges
fonte
3

A resposta aceita não funcionará para duplicatas na coleção. Se você estiver definido como foreach, basta adicionar suas próprias variáveis ​​de indexação.

int last = Model.Results.Count - 1;
int index = 0;
foreach (Item result in Model.Results)
{
    //Do Things

    if (index == last)
        //Do Things with the last result

    index++;
}
Ehryk
fonte
2

usando o Linq e o foreach:

foreach (Item result in Model.Results)   
{   
     if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
             // this is the last item
     }
}

https://code.i-harness.com/en/q/7213ce

HanMyintTun
fonte
1
isso funcionará apenas se a lista / coleção tiver valores exclusivos.
Melleck
1

".Last ()" não funcionou para mim, então eu tive que fazer algo assim:

Dictionary<string, string> iterativeDictionary = someOtherDictionary;
var index = 0;
iterativeDictionary.ForEach(kvp => 
    index++ == iterativeDictionary.Count ? 
        /*it's the last item */ :
        /*it's not the last item */
);
itcropper
fonte
1

Fazendo alguns pequenos ajustes no excelente código de Jon Skeet, você pode até torná-lo mais inteligente, permitindo o acesso ao item anterior e ao próximo. Obviamente, isso significa que você terá que ler um item à frente na implementação. Por motivos de desempenho, o item anterior e o próximo são retidos apenas para o item de iteração atual. É assim:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// Based on source: http://jonskeet.uk/csharp/miscutil/

namespace Generic.Utilities
{
    /// <summary>
    /// Static class to make creation easier. If possible though, use the extension
    /// method in SmartEnumerableExt.
    /// </summary>
    public static class SmartEnumerable
    {
        /// <summary>
        /// Extension method to make life easier.
        /// </summary>
        /// <typeparam name="T">Type of enumerable</typeparam>
        /// <param name="source">Source enumerable</param>
        /// <returns>A new SmartEnumerable of the appropriate type</returns>
        public static SmartEnumerable<T> Create<T>(IEnumerable<T> source)
        {
            return new SmartEnumerable<T>(source);
        }
    }

    /// <summary>
    /// Type chaining an IEnumerable&lt;T&gt; to allow the iterating code
    /// to detect the first and last entries simply.
    /// </summary>
    /// <typeparam name="T">Type to iterate over</typeparam>
    public class SmartEnumerable<T> : IEnumerable<SmartEnumerable<T>.Entry>
    {

        /// <summary>
        /// Enumerable we proxy to
        /// </summary>
        readonly IEnumerable<T> enumerable;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="enumerable">Collection to enumerate. Must not be null.</param>
        public SmartEnumerable(IEnumerable<T> enumerable)
        {
            if (enumerable == null)
            {
                throw new ArgumentNullException("enumerable");
            }
            this.enumerable = enumerable;
        }

        /// <summary>
        /// Returns an enumeration of Entry objects, each of which knows
        /// whether it is the first/last of the enumeration, as well as the
        /// current value and next/previous values.
        /// </summary>
        public IEnumerator<Entry> GetEnumerator()
        {
            using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
            {
                if (!enumerator.MoveNext())
                {
                    yield break;
                }
                bool isFirst = true;
                bool isLast = false;
                int index = 0;
                Entry previous = null;

                T current = enumerator.Current;
                isLast = !enumerator.MoveNext();
                var entry = new Entry(isFirst, isLast, current, index++, previous);                
                isFirst = false;
                previous = entry;

                while (!isLast)
                {
                    T next = enumerator.Current;
                    isLast = !enumerator.MoveNext();
                    var entry2 = new Entry(isFirst, isLast, next, index++, entry);
                    entry.SetNext(entry2);
                    yield return entry;

                    previous.UnsetLinks();
                    previous = entry;
                    entry = entry2;                    
                }

                yield return entry;
                previous.UnsetLinks();
            }
        }

        /// <summary>
        /// Non-generic form of GetEnumerator.
        /// </summary>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// Represents each entry returned within a collection,
        /// containing the value and whether it is the first and/or
        /// the last entry in the collection's. enumeration
        /// </summary>
        public class Entry
        {
            #region Fields
            private readonly bool isFirst;
            private readonly bool isLast;
            private readonly T value;
            private readonly int index;
            private Entry previous;
            private Entry next = null;
            #endregion

            #region Properties
            /// <summary>
            /// The value of the entry.
            /// </summary>
            public T Value { get { return value; } }

            /// <summary>
            /// Whether or not this entry is first in the collection's enumeration.
            /// </summary>
            public bool IsFirst { get { return isFirst; } }

            /// <summary>
            /// Whether or not this entry is last in the collection's enumeration.
            /// </summary>
            public bool IsLast { get { return isLast; } }

            /// <summary>
            /// The 0-based index of this entry (i.e. how many entries have been returned before this one)
            /// </summary>
            public int Index { get { return index; } }

            /// <summary>
            /// Returns the previous entry.
            /// Only available for the CURRENT entry!
            /// </summary>
            public Entry Previous { get { return previous; } }

            /// <summary>
            /// Returns the next entry for the current iterator.
            /// Only available for the CURRENT entry!
            /// </summary>
            public Entry Next { get { return next; } }
            #endregion

            #region Constructors
            internal Entry(bool isFirst, bool isLast, T value, int index, Entry previous)
            {
                this.isFirst = isFirst;
                this.isLast = isLast;
                this.value = value;
                this.index = index;
                this.previous = previous;
            }
            #endregion

            #region Methods
            /// <summary>
            /// Fix the link to the next item of the IEnumerable
            /// </summary>
            /// <param name="entry"></param>
            internal void SetNext(Entry entry)
            {
                next = entry;
            }

            /// <summary>
            /// Allow previous and next Entry to be garbage collected by setting them to null
            /// </summary>
            internal void UnsetLinks()
            {
                previous = null;
                next = null;
            }

            /// <summary>
            /// Returns "(index)value"
            /// </summary>
            /// <returns></returns>
            public override string ToString()
            {
                return String.Format("({0}){1}", Index, Value);
            }
            #endregion

        }
    }
}
Edwin
fonte
1

Como converter foreachpara reagir ao último elemento:

List<int> myList = new List<int>() {1, 2, 3, 4, 5};
Console.WriteLine("foreach version");
{
    foreach (var current in myList)
    {
        Console.WriteLine(current);
    }
}
Console.WriteLine("equivalent that reacts to last element");
{
    var enumerator = myList.GetEnumerator();
    if (enumerator.MoveNext() == true) // Corner case: empty list.
    {
        while (true)
        {
            int current = enumerator.Current;

            // Handle current element here.
            Console.WriteLine(current);

            bool ifLastElement = (enumerator.MoveNext() == false);
            if (ifLastElement)
            {
                // Cleanup after last element
                Console.WriteLine("[last element]");
                break;
            }
        }
    }
    enumerator.Dispose();
}
Contango
fonte
1

Apenas armazene o valor anterior e trabalhe com ele dentro do loop. Então, no final, o valor 'anterior' será o último item, permitindo que você o manipule de maneira diferente. Nenhuma biblioteca especial ou de contagem é necessária.

bool empty = true;
Item previousItem;

foreach (Item result in Model.Results)
{
    if (!empty)
    {
        // We know this isn't the last item because it came from the previous iteration
        handleRegularItem(previousItem);
    }

    previousItem = result;
    empty = false;
}

if (!empty)
{
    // We know this is the last item because the loop is finished
    handleLastItem(previousItem);
}
voltrevo
fonte
1

Você pode usar um loop for e não há necessidade de adicionar um extra ifdentro do forcorpo:

for (int i = 0; i < Model.Results.Count - 1; i++) {
    var item = Model.Results[i];
}

A -1na forcondição cuida de pular o último item.

Alisson
fonte
O -1 no loop for não ignora o último item. Você obteria um IndexOutOfRangeException se não incluísse o -1.
Jaa H
0

Para fazer algo adicional a cada elemento, exceto o último, a abordagem baseada em funções pode ser usada.

delegate void DInner ();

....
    Dinner inner=delegate 
    { 
        inner=delegate 
        { 
            // do something additional
        } 
    }
    foreach (DataGridViewRow dgr in product_list.Rows)
    {
        inner()
        //do something
    }
}

Essa abordagem tem desvantagens aparentes: menos clareza de código para casos mais complexos. Ligar para os delegados pode não ser muito eficaz. A solução de problemas pode não ser muito fácil. O lado positivo - a codificação é divertida!

Dito isto, sugiro o uso de plain para loops em casos triviais, se você souber que a contagem de sua coleção não é muito lenta.

dmitry
fonte
0

Outra maneira, que eu não vi postada, é usar uma Fila. É análogo a uma maneira de implementar um método SkipLast () sem repetir mais do que o necessário. Dessa forma, você também poderá fazer isso em qualquer número de últimos itens.

public static void ForEachAndKnowIfLast<T>(
    this IEnumerable<T> source,
    Action<T, bool> a,
    int numLastItems = 1)
{
    int bufferMax = numLastItems + 1;
    var buffer = new Queue<T>(bufferMax);
    foreach (T x in source)
    {
        buffer.Enqueue(x);
        if (buffer.Count < bufferMax)
            continue; //Until the buffer is full, just add to it.
        a(buffer.Dequeue(), false);
    }
    foreach (T item in buffer)
        a(item, true);
}

Para chamar isso, faça o seguinte:

Model.Results.ForEachAndKnowIfLast(
    (result, isLast) =>
    {
        //your logic goes here, using isLast to do things differently for last item(s).
    });
rrreee
fonte
0
     List<int> ListInt = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };


                int count = ListInt.Count;
                int index = 1;
                foreach (var item in ListInt)
                {
                    if (index != count)
                    {
                        Console.WriteLine("do something at index number  " + index);
                    }
                    else
                    {
                        Console.WriteLine("Foreach loop, this is the last iteration of the loop " + index);
                    }
                    index++;

                }
 //OR
                int count = ListInt.Count;
                int index = 1;
                foreach (var item in ListInt)
                {
                    if (index < count)
                    {
                        Console.WriteLine("do something at index number  " + index);
                    }
                    else
                    {
                        Console.WriteLine("Foreach loop, this is the last iteration of the loop " + index);
                    }
                    index++;

                }
Zoyeb Shaikh
fonte
0

Você pode criar um método de extensão especialmente dedicado a isso:

public static class EnumerableExtensions {
    public static bool IsLast<T>(this List<T> items, T item)
        {
            if (items.Count == 0)
                return false;
            T last = items[items.Count - 1];
            return item.Equals(last);
        }
    }

e você pode usá-lo assim:

foreach (Item result in Model.Results)
{
    if(Model.Results.IsLast(result))
    {
        //do something in the code
    }
}
A. Morel
fonte
0

Com base na resposta de @ Shimmy, criei um método de extensão que é a solução que todos desejam. É simples, fácil de usar e apenas percorre a coleção uma vez.

internal static class EnumerableExtensions
{
    public static void ForEachLast<T>(this IEnumerable<T> collection, Action<T>? actionExceptLast = null, Action<T>? actionOnLast = null)
    {
        using var enumerator = collection.GetEnumerator();
        var isNotLast = enumerator.MoveNext();
        while (isNotLast)
        {
            var current = enumerator.Current;
            isNotLast = enumerator.MoveNext();
            var action = isNotLast ? actionExceptLast : actionOnLast;
            action?.Invoke(current);
        }
    }
}

Isso funciona em qualquer IEnumerable<T>. O uso fica assim:

var items = new[] {1, 2, 3, 4, 5};
items.ForEachLast(i => Console.WriteLine($"{i},"), i => Console.WriteLine(i));

A saída se parece com:

1,
2,
3,
4,
5

Além disso, você pode transformar isso em um Selectmétodo de estilo. Em seguida, reutilize essa extensão no ForEach. Esse código fica assim:

internal static class EnumerableExtensions
{
    public static void ForEachLast<T>(this IEnumerable<T> collection, Action<T>? actionExceptLast = null, Action<T>? actionOnLast = null) =>
        // ReSharper disable once IteratorMethodResultIsIgnored
        collection.SelectLast(i => { actionExceptLast?.Invoke(i); return true; }, i => { actionOnLast?.Invoke(i); return true; }).ToArray();

    public static IEnumerable<TResult> SelectLast<T, TResult>(this IEnumerable<T> collection, Func<T, TResult>? selectorExceptLast = null, Func<T, TResult>? selectorOnLast = null)
    {
        using var enumerator = collection.GetEnumerator();
        var isNotLast = enumerator.MoveNext();
        while (isNotLast)
        {
            var current = enumerator.Current;
            isNotLast = enumerator.MoveNext();
            var selector = isNotLast ? selectorExceptLast : selectorOnLast;
            //https://stackoverflow.com/a/32580613/294804
            if (selector != null)
            {
                yield return selector.Invoke(current);
            }
        }
    }
}
Michael Yanni
fonte
-1

Podemos verificar o último item em loop.

foreach (Item result in Model.Results)
{
    if (result==Model.Results.Last())
    {
        // do something different with the last item
    }
}
Bashir Momen
fonte
-2
foreach (DataRow drow in ds.Tables[0].Rows)
            {
                cnt_sl1 = "<div class='col-md-6'><div class='Slider-img'>" +
                          "<div class='row'><img src='" + drow["images_path"].ToString() + "' alt='' />" +
                          "</div></div></div>";
                cnt_sl2 = "<div class='col-md-6'><div class='Slider-details'>" +
                          "<p>" + drow["situation_details"].ToString() + "</p>" +
                          "</div></div>";
                if (i == 0)
                {
                    lblSituationName.Text = drow["situation"].ToString();
                }
                if (drow["images_position"].ToString() == "0")
                {
                    content += "<div class='item'>" + cnt_sl1 + cnt_sl2 + "</div>";
                    cnt_sl1 = "";
                    cnt_sl2 = "";
                }
                else if (drow["images_position"].ToString() == "1")
                {
                    content += "<div class='item'>" + cnt_sl2 + cnt_sl1 + "</div>";
                    cnt_sl1 = "";
                    cnt_sl2 = "";
                }
                i++;
            }

fonte
(!) Não importa quão bom ou ruim seu código seja. Sem uma explicação, geralmente não tem valor.
22418 AlexMelw
Também parece um excesso de engenharia.
mecograph
-3

Você pode fazer assim:

foreach (DataGridViewRow dgr in product_list.Rows)
{
    if (dgr.Index == dgr.DataGridView.RowCount - 1)
    {
        //do something
    }
}
Sheharyar
fonte