Foreach loop, determinare qual è l'ultima iterazione del loop


233

Ho un foreachciclo e ho bisogno di eseguire un po 'di logica quando l'ultimo elemento viene scelto dal List, ad esempio:

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

Posso sapere quale ciclo è l'ultimo senza usare per loop e contatori?


1
Dai un'occhiata alla mia risposta qui per una soluzione che ho pubblicato per una domanda correlata.
Brian Gideon,

Risposte:


294

Se hai solo bisogno di fare qualcosa con l'ultimo elemento (al contrario di qualcosa di diverso con l'ultimo elemento, l'utilizzo di LINQ ti aiuterà qui:

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

Se hai bisogno di fare qualcosa di diverso con l'ultimo elemento, allora avresti bisogno di qualcosa come:

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

Anche se probabilmente dovresti scrivere un comparatore personalizzato per assicurarti di poter dire che l'articolo era lo stesso dell'articolo restituito Last().

Questo approccio deve essere utilizzato con cautela, poiché Lastpotrebbe essere necessario ripetere la raccolta. Mentre questo potrebbe non essere un problema per le piccole raccolte, se diventa grande potrebbe avere implicazioni sulle prestazioni. Non funzionerà anche se l'elenco contiene elementi duplicati. In questi casi qualcosa di simile potrebbe essere più appropriato:

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

1
Quello di cui avevo bisogno era: quando il ciclo passa attraverso l'ultimo elemento: foreach (Item item in Model.Results) {if (result == Model.Results.Last ()) {<div> last </div>; } Sembra che tu abbia praticamente inteso la stessa cosa.
incidente

10
Il codice eseguirà l'iterazione due volte attraverso l'intera raccolta, male se la raccolta non è piccola. Vedi questa risposta
Shimmy Weitzhandler,

54
Questo non funziona davvero se hai duplicati nella tua raccolta. Ad esempio, se stai lavorando con una raccolta di stringhe e ci sono duplicati, quel codice "diverso dall'ultimo elemento" verrà eseguito per ogni occorrenza dell'ultimo elemento nell'elenco.
Muttley91,

7
Questa risposta è vecchia, ma per gli altri che guardano questa risposta, puoi ottenere l'ultimo elemento e assicurarti di non dover passare in rassegna gli elementi usando: Item last = Model.Results [Model.Results.Count - 1] Il conteggio la proprietà di un elenco non richiede il loop. Se hai duplicati nel tuo elenco, usa semplicemente una variabile iteratore in un ciclo for. I vecchi regolari per i loop non sono male.
Michael Harris,

Suggerisco di usare var last = Model.Result[Model.Result.Count - 1];più velocemente dell'usoLast()
Tân

184

Che ne dici di un buon vecchio stile per loop?

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

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

O usando Linq e the foreach:

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

14
Così tante persone che pensano troppo a un semplice problema come questo, quando il ciclo for è perfettamente in grado di farlo già. : \
Andrew Hoffman,

La soluzione Linq è la mia preferita in assoluto! Grazie per la condivisione
mecograph

Questa è la risposta più appropriata di quella accettata.
Ratul,

Nota per chiunque desideri utilizzare la soluzione LINQ su una raccolta di stringhe (o tipi di valore): generalmente non funzionerà perché il confronto == fallirà se l'ultima stringa nell'elenco appare anche prima nell'elenco. Funzionerebbe solo se stai lavorando con un elenco garantito senza stringhe duplicate.
Tawab Wakil,

Purtroppo non è possibile utilizzare questa soluzione intelligente se Model.Resultsè un IEnumerable. È possibile chiamare Count()prima del ciclo, ma ciò può causare l'iterazione completa della sequenza.
Luca Cremonesi,

42

Usando Last()su alcuni tipi passerà attraverso l'intera collezione!
Ciò significa che se fai un foreache chiedi Last(), sei in loop due volte!che sono sicuro che vorresti evitare nelle grandi collezioni.

Quindi la soluzione è utilizzare un 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
  }
}

Pertanto, a meno che il tipo di raccolta non sia di tipo, IList<T>la Last()funzione eseguirà l'iterazione attraverso tutti gli elementi della raccolta.

Test

Se la tua raccolta fornisce un accesso casuale (ad esempio strumenti IList<T>), puoi anche controllare il tuo articolo come segue.

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps

1
Sei sicuro che l'enumeratore abbia bisogno di una usingdichiarazione? Ho pensato che fosse necessario solo se un oggetto gestisce le risorse del sistema operativo, ma non per le strutture di dati gestite.
Gattino accovacciato

IEnumerator non implementa IDisposable, quindi la linea con l'utilizzo con solleva un errore di compilazione! +1 per la soluzione, il più delle volte non possiamo semplicemente usare a for anziché foreach, poiché gli elementi delle raccolte enumerabili vengono calcolati in fase di esecuzione o la sequenza non supporta l'accesso casuale.
Saleh,


40

Come dimostra Chris, Linq funzionerà; basta usare Last () per ottenere un riferimento all'ultimo dell'enumerabile e fintanto che non si lavora con quel riferimento, fare il proprio codice normale, ma se si sta lavorando con quel riferimento, fare la propria cosa in più. Il rovescio della medaglia è che sarà sempre la complessità O (N).

Puoi invece usare Count () (che è O (1) se IEnumerable è anche un ICollection; questo è vero per la maggior parte dei comuni IEnumerables incorporati) e ibridi il tuo foreach con un contatore:

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

22
foreach (var item in objList)
{
  if(objList.LastOrDefault().Equals(item))
  {

  }
}

Ciao, questo è l'approccio migliore finora! Semplice e al punto. Un approccio da programmatore, uno. Perché non scegliamo e diamo questo +1 sempre di più!
Hanny Setiawan,

1
L'ultimo elemento deve essere trovato una sola volta ( Promuovi memoization ) prima del foreachblocco. Come questo: var lastItem = objList.LastOrDeafault();. Poi dall'interno del foreachloop che si potrebbe verificare in questo modo: f (item.Equals(lastItem)) { ... }. Nella tua risposta originale, objList.LastOrDefault()verrebbe ripetuto la raccolta in corrispondenza di ogni iterazione "foreach" ( è coinvolta la complessità polinomiale ).
AlexMelw,

Cattiva risposta. n ^ 2 complessità invece di n.
Shimmy Weitzhandler,

11

Come ha sottolineato Shimmy, l'utilizzo di Last () può essere un problema di prestazioni, ad esempio se la tua raccolta è il risultato live di un'espressione LINQ. Per evitare più iterazioni, è possibile utilizzare un metodo di estensione "ForEach" come questo:

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

Il metodo di estensione è simile al seguente (come bonus aggiuntivo, ti dirà anche l'indice e se stai guardando il primo 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; }
    }
}

9

Migliorando ulteriormente la risposta di Daniel Wolf, potresti impilarne un'altra IEnumerableper evitare più iterazioni e lambda come:

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

L'implementazione del metodo di estensione:

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

1
L'altra risposta non ripeterà più volte l'origine, quindi non è un problema che stai risolvendo. Hai davvero permesso l'uso di foreach, il che è un miglioramento.
Servito il

1
@Servy intendo quello. Oltre alla singola iterazione dalla risposta originale, sto evitando lambdas.
Fabricio Godoy,

7

L'implementazione dell'iteratore non lo prevede. La tua raccolta potrebbe essere IListaccessibile tramite un indice in O (1). In tal caso puoi usare un normale for-loop:

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

Se conosci il conteggio, ma non riesci ad accedere tramite gli indici (quindi, il risultato è un ICollection), puoi contare te stesso incrementando un inelforeach corpo del e confrontandolo con la lunghezza.

Tutto ciò non è perfettamente elegante. La soluzione di Chris potrebbe essere la più bella che abbia mai visto finora.


Nel confrontare le prestazioni del tuo contatore all'interno dell'idea foreach con la soluzione di Chris, mi chiedo quale costerebbe di più: una singola chiamata Last () o la somma di tutte le operazioni di incremento aggiunte. Sospetto che sarebbe vicino.
TTT

6

Che dire dell'approccio un po 'più semplice.

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

2
Non so perché qualcuno ti abbia votato male. Questo è perfettamente accettabile considerando che stai già eseguendo una foreach e stai sostenendo il costo di o (n).
Arviman,

2
Nonostante la risposta sia perfetta per scoprire l'ultimo elemento, non soddisfa le condizioni dell'OP " ..., determinare quale è l'ultima iterazione del ciclo ". Quindi, non sei in grado di determinare che l'ultima iterazione sia effettivamente l'ultima e, quindi, non puoi gestirla diversamente o addirittura ignorarla. Questo è il motivo per cui qualcuno ti ha sottovalutato. @arviman ne eri così curioso.
AlexMelw,

1
Hai ragione, mi mancava del tutto @ Andrey-WD. Immagino che la soluzione da risolvere sia chiamare "last" una volta prima del loop (non è possibile farlo all'interno del loop come sarebbe O (N ^ 2) e quindi verificare se il riferimento corrisponde.
Arviman,

5

L'approccio migliore sarebbe probabilmente solo quello di eseguire quel passaggio dopo il ciclo: ad es

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

//Post execution logic

O se devi fare qualcosa per l'ultimo risultato

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

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

//Execute logic on lastItem here

3

La risposta accettata non funzionerà per i duplicati nella raccolta. Se sei impostato su foreach, puoi semplicemente aggiungere le tue variabili di indicizzazione.

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


1

".Last ()" non ha funzionato per me, quindi ho dovuto fare qualcosa del genere:

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 */
);

1

Apportando alcune piccole modifiche al codice eccellente di Jon Skeet, puoi persino renderlo più intelligente consentendo l'accesso all'elemento precedente e successivo. Ovviamente questo significa che dovrai leggere in anticipo 1 elemento dell'implementazione. Per motivi di prestazioni, l'elemento precedente e successivo vengono conservati solo per l'elemento di iterazione corrente. Va così:

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

        }
    }
}

1

Come convertire foreachper reagire all'ultimo 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();
}

1

Memorizza semplicemente il valore precedente e lavora con esso all'interno del loop. Quindi alla fine il valore "precedente" sarà l'ultimo elemento, permettendoti di gestirlo in modo diverso. Non sono necessarie librerie di conteggio o speciali.

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

1

Potresti semplicemente usare un ciclo for e non è necessario aggiungere un extra ifall'interno del forcorpo:

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

L' -1nella forcondizione di si occupa di saltare l'ultimo elemento.


Il -1 nel ciclo for non si occupa di saltare l'ultimo elemento. Otterresti un IndexOutOfRangeException se non includessi -1.
Jaa H,


0

Per fare qualcosa in più per ogni elemento tranne l'ultimo, è possibile utilizzare un approccio basato sulle funzioni.

delegate void DInner ();

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

Questo approccio presenta evidenti inconvenienti: minore chiarezza del codice per casi più complessi. La chiamata dei delegati potrebbe non essere molto efficace. La risoluzione dei problemi potrebbe non essere abbastanza semplice. Il lato positivo: la codifica è divertente!

Detto questo, suggerirei di usare plain for loop in casi banali, se sai che il conteggio della tua collezione non è tremendamente lento.


0

Un altro modo, che non ho visto pubblicato, è utilizzare una coda. È analogo al modo di implementare un metodo SkipLast () senza ripetere più del necessario. In questo modo ti permetterà anche di farlo su qualsiasi numero di ultimi elementi.

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

Per chiamare questo dovresti fare quanto segue:

Model.Results.ForEachAndKnowIfLast(
    (result, isLast) =>
    {
        //your logic goes here, using isLast to do things differently for last item(s).
    });

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++;

                }

0

Puoi creare un metodo di estensione appositamente dedicato a questo:

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 puoi usarlo in questo modo:

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

0

Sulla base della risposta di @ Shimmy, ho creato un metodo di estensione che è la soluzione che tutti vogliono. È semplice, facile da usare e scorre una sola volta nella raccolta.

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

Questo funziona su qualsiasi IEnumerable<T>. L'utilizzo è simile al seguente:

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

L'output è simile a:

1,
2,
3,
4,
5

Inoltre, puoi trasformarlo in un Selectmetodo di stile. Quindi, riutilizzare tale estensione in ForEach. Questo codice è simile al seguente:

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

-1

Possiamo controllare l'ultimo elemento in loop.

foreach (Item result in Model.Results)
{
    if (result==Model.Results.Last())
    {
        // do something different with the last item
    }
}

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

(!) Non importa quanto sia buono o cattivo il tuo codice. Senza una spiegazione di solito non ha valore.
AlexMelw,

Inoltre sembra troppo ingegnerizzato.
mecografo

-3

Puoi fare così:

foreach (DataGridViewRow dgr in product_list.Rows)
{
    if (dgr.Index == dgr.DataGridView.RowCount - 1)
    {
        //do something
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.