Para cada ciclo, determine cuál es la última iteración del ciclo

233

Tengo un foreachbucle y necesito ejecutar algo de lógica cuando se elige el último elemento List, por ejemplo:

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

¿Puedo saber qué ciclo es el último sin usar para ciclo y contadores?

percance
fuente
1
Eche un vistazo a mi respuesta aquí para obtener una solución que publiqué en una pregunta relacionada.
Brian Gideon

Respuestas:

294

Si solo necesita hacer algo con el último elemento (a diferencia de algo diferente con el último elemento, usar LINQ lo ayudará aquí:

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

Si necesita hacer algo diferente con el último elemento, necesitaría 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
    }
}

Aunque es probable que necesite escribir un comparador personalizado para asegurarse de que pueda decir que el artículo fue el mismo que devolvió el artículo Last().

Este enfoque debe usarse con precaución, ya que es Lastposible que tenga que iterar a través de la colección. Si bien esto podría no ser un problema para las colecciones pequeñas, si se hace grande podría tener implicaciones de rendimiento. También fallará si la lista contiene elementos duplicados. En estos casos, algo como esto puede ser más apropiado:

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
fuente
1
Lo que necesitaba era: Cuando el ciclo atraviesa su último elemento: foreach (Resultado del elemento en Model.Results) {if (result == Model.Results.Last ()) {<div> last </div>; } Parece que querías decir lo mismo.
accidente
10
Su código iterará dos veces a través de toda la colección, malo si la colección no es pequeña. Mira esta respuesta.
Shimmy Weitzhandler
54
Esto realmente no funciona si tienes duplicados en tu colección. Por ejemplo, si está trabajando con una colección de cadenas, y hay duplicados, entonces ese código "diferente con el último elemento" se ejecutará para cada aparición del último elemento en la lista.
muttley91
77
Esta respuesta es antigua, pero para los demás que la miran, puede obtener el último elemento y asegurarse de que no tiene que recorrer los elementos utilizando: Item last = Model.Results [Model.Results.Count - 1] El recuento La propiedad de una lista no requiere bucle. Si tiene duplicados en su lista, simplemente use una variable iteradora en un bucle for. Los viejos regulares para bucles no son malos.
Michael Harris
Sugiero usar var last = Model.Result[Model.Result.Count - 1];más rápido que usarLast()
Tân
184

¿Qué tal un buen bucle pasado de moda?

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

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

O usando Linq y el foreach:

foreach (Item result in Model.Results)   
{   
     if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
             // this is the last item
     }
}
Fiona - myaccessible.website
fuente
14
Muchas personas piensan demasiado en un problema simple como este, cuando el ciclo for ya es perfectamente capaz de hacerlo. : \
Andrew Hoffman
¡La solución Linq es mi favorita absoluta! Gracias por compartir
mecograph
Esta es la respuesta más apropiada que la aceptada.
Ratul
Nota para cualquiera que quiera usar la solución LINQ en una colección de cadenas (o tipos de valor): generalmente no funcionará porque la comparación == fallará si la última cadena de la lista también aparece antes en la lista. Solo funcionaría si está trabajando con una lista garantizada que no tiene cadenas duplicadas.
Tawab Wakil
Lamentablemente, no puede utilizar esta solución inteligente si Model.Resultses un IEnumerable. Puede llamar Count()antes del ciclo pero eso puede causar la iteración completa de la secuencia.
Luca Cremonesi
42

¡El uso Last()en ciertos tipos recorrerá toda la colección!
Lo que significa que si haces una foreachllamada y Last()llamaste dos veces. que estoy seguro de que te gustaría evitar en grandes colecciones.

Entonces la solución es usar un do whilebucle:

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

Entonces, a menos que el tipo de colección sea de tipo, IList<T>la Last()función iterará a través de todos los elementos de la colección.

Prueba

Si su colección proporciona acceso aleatorio (por ejemplo, implementos IList<T>), también puede verificar su artículo de la siguiente manera.

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps
Shimmy Weitzhandler
fuente
1
¿Estás seguro de que el enumerador necesita una usingdeclaración? Pensé que solo era necesario si un objeto maneja los recursos del sistema operativo, pero no para las estructuras de datos administrados.
Gatito
¡IEnumerator no implementa IDisposable, por lo que la línea con el uso genera un error de tiempo de compilación! +1 para la solución, la mayoría de las veces no podemos simplemente usar un for en lugar de foreach, porque los elementos de colecciones enumerables se calculan en tiempo de ejecución o la secuencia no admite acceso aleatorio.
Saleh
1
El genérico sí.
Shimmy Weitzhandler
40

Como muestra Chris, Linq funcionará; solo use Last () para obtener una referencia al último en el enumerable, y siempre que no esté trabajando con esa referencia, entonces haga su código normal, pero si ESTÁ trabajando con esa referencia, haga su trabajo adicional. Su desventaja es que siempre será una complejidad O (N).

En su lugar, puede usar Count () (que es O (1) si IEnumerable también es una ICollection; esto es cierto para la mayoría de los IEnumerables incorporados comunes) e híbrir su foreach con un contador:

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

  }
}
Gabriel Tiburcio
fuente
Hola, este es el mejor enfoque hasta ahora. Simple y al grano. Un enfoque de programador, uno. ¿Por qué no elegimos y le damos a este +1 más y más!
Hanny Setiawan
1
El último elemento se debe encontrar solo una vez ( Promover memorización ) antes del foreachbloqueo. De esta manera: var lastItem = objList.LastOrDeafault();. A continuación, desde el interior del foreachbucle se puede comprobar de esta manera: f (item.Equals(lastItem)) { ... }. En su respuesta original objList.LastOrDefault(), iteraría sobre la colección en cada iteración "foreach" (la complejidad polinomial está involucrada ).
AlexMelw
Mala respuesta. n ^ 2 complejidad en lugar de n.
Shimmy Weitzhandler
11

Como Shimmy ha señalado, usar Last () puede ser un problema de rendimiento, por ejemplo, si su colección es el resultado en vivo de una expresión LINQ. Para evitar múltiples iteraciones, puede usar un método de extensión "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);
    }
});

El método de extensión se ve así (como una ventaja adicional, también le indicará el índice y, si está viendo el primer 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
fuente
9

Mejorando aún más la respuesta de Daniel Wolf , podría apilarse en otra IEnumerablepara evitar múltiples iteraciones y 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);
    }
}

La implementación del método de extensión:

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
fuente
1
La otra respuesta no repite la fuente varias veces, por lo que no es un problema que esté solucionando. De hecho, ha permitido el uso de foreach, que es una mejora.
Servicio
1
@Servy, quiero decir eso. Además de la iteración única de la respuesta original, estoy evitando las lambdas.
Fabricio Godoy
7

La implementación del iterador no proporciona eso. Su colección puede ser IListaccesible mediante un índice en O (1). En ese caso, puede usar un forbucle normal :

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

Si conoce el recuento, pero no puede acceder a través de los índices (por lo tanto, el resultado es un ICollection), puede contar usted mismo incrementando un ien el foreachcuerpo y comparándolo con la longitud.

Todo esto no es perfectamente elegante. La solución de Chris puede ser la mejor que he visto hasta ahora.

Matthias Meid
fuente
Al comparar el rendimiento de su contador dentro de la idea foreach frente a la solución de Chris, me pregunto cuál costaría más: una sola llamada Last (), o la suma de todas las operaciones de incremento agregado. Sospecho que estaría cerca.
TTT
6

¿Qué pasa con un enfoque poco más simple?

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
fuente
2
No sé por qué alguien te rechazó. Esto es perfectamente aceptable teniendo en cuenta que ya está realizando un foreach y está incurriendo en el costo de o (n).
arviman
2
A pesar de que la respuesta es perfecta para descubrir el último elemento, no se ajusta a la condición del OP " ..., determine cuál es la última iteración del bucle ". Por lo tanto, no puede determinar que la última iteración sea en realidad la última y, por lo tanto, no podría manejarla de manera diferente o incluso ignorarla. Esa es la razón por la que alguien te ha rechazado. @arviman tenías tanta curiosidad al respecto.
AlexMelw
1
Tienes razón, lo extrañé totalmente @ Andrey-WD. Supongo que la solución para solucionarlo es llamar "último" una vez antes del ciclo (no puede hacerlo dentro del ciclo como sería O (N ^ 2) y luego verificar si la referencia coincide.
arviman
5

El mejor enfoque probablemente sería simplemente ejecutar ese paso después del ciclo: por ejemplo

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

//Post execution logic

O si necesita hacer algo para el ú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
fuente
3

La respuesta aceptada no funcionará para duplicados en la colección. Si está configurado en foreach, simplemente puede agregar sus propias variables de indexación.

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
fuente
2

usando Linq y el 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
fuente
1
esto solo funcionará si la lista / colección tiene valores únicos.
melleck
1

".Last ()" no funcionó para mí, así que tuve que hacer algo como esto:

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
fuente
1

Haciendo algunos pequeños ajustes al excelente código de Jon Skeet, incluso puede hacerlo más inteligente al permitir el acceso al elemento anterior y siguiente. Por supuesto, esto significa que tendrá que leer con anticipación 1 elemento en la implementación. Por razones de rendimiento, el elemento anterior y el siguiente solo se retienen para el elemento de iteración actual. Dice así:

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
fuente
1

Cómo convertir foreachpara reaccionar al ú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();
}
Aplazamiento de pago
fuente
1

Simplemente almacene el valor anterior y trabaje con él dentro del ciclo. Luego, al final, el valor 'anterior' será el último elemento, lo que le permitirá manejarlo de manera diferente. No se requieren conteo ni bibliotecas especiales.

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
fuente
1

Puede usar un bucle for y no es necesario agregar un extra ifdentro del forcuerpo:

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

El -1en la forcondición se encarga de omitir el último elemento.

Alisson
fuente
El -1 en el bucle for no se ocupa de omitir el último elemento. Obtendría una IndexOutOfRangeException si no incluyera el -1.
Jaa H
0

Para hacer algo adicional a cada elemento, excepto el último, se puede utilizar el enfoque basado en funciones.

delegate void DInner ();

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

Este enfoque tiene inconvenientes aparentes: menos claridad de código para casos más complejos. Llamar a los delegados podría no ser muy efectivo. La resolución de problemas podría no ser tan fácil. El lado positivo: ¡la codificación es divertida!

Dicho esto, sugeriría usar plain for loops en casos triviales, si sabes que el recuento de tu colección no es terriblemente lento.

dmitry
fuente
0

Otra forma, que no vi publicada, es usar una cola. Es análogo a una forma de implementar un método SkipLast () sin iterar más de lo necesario. De esta manera también le permitirá hacer esto en cualquier número de últimos elementos.

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 llamar a esto, haría lo siguiente:

Model.Results.ForEachAndKnowIfLast(
    (result, isLast) =>
    {
        //your logic goes here, using isLast to do things differently for last item(s).
    });
rrreee
fuente
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
fuente
0

Puede hacer un método de extensión especialmente dedicado a esto:

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);
        }
    }

y puedes usarlo así:

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

Basado en la respuesta de @ Shimmy, creé un método de extensión que es la solución que todos quieren. Es simple, fácil de usar y solo recorre la colección una 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);
        }
    }
}

Esto funciona en cualquiera IEnumerable<T>. El uso se ve así:

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

La salida se ve así:

1,
2,
3,
4,
5

Además, puede convertir esto en un Selectmétodo de estilo. Luego, reutilice esa extensión en ForEach. Ese código se ve así:

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
fuente
-1

Podemos verificar el último elemento en bucle.

foreach (Item result in Model.Results)
{
    if (result==Model.Results.Last())
    {
        // do something different with the last item
    }
}
Bashir Momen
fuente
-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++;
            }

fuente
(!) No importa cuán bueno o malo sea su código. Sin una explicación, generalmente no tiene valor.
AlexMelw
También parece demasiado diseñado.
mecógrafo
-3

Puedes hacer así:

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