Pour chaque boucle, déterminez quelle est la dernière itération de la boucle

233

J'ai une foreachboucle et j'ai besoin d'exécuter une logique lorsque le dernier élément est choisi dans le List, par exemple:

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

Puis-je savoir quelle boucle est la dernière sans utiliser de boucle et de compteurs?

mésaventure
la source
1
Jetez un oeil à ma réponse ici pour une solution que j'ai postée à une question connexe.
Brian Gideon

Réponses:

294

Si vous avez juste besoin de faire quelque chose avec le dernier élément (par opposition à quelque chose de différent avec le dernier élément, l'utilisation de LINQ vous aidera ici:

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

Si vous devez faire quelque chose de différent avec le dernier élément, vous aurez besoin de quelque chose comme:

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

Bien que vous deviez probablement écrire un comparateur personnalisé pour vous assurer que vous pouviez dire que l'article était le même que l'article retourné par Last().

Cette approche doit être utilisée avec prudence car il se Lastpourrait bien qu'elle doive parcourir la collection. Bien que cela ne soit pas un problème pour les petites collections, s'il devient volumineux, cela peut avoir des implications sur les performances. Il échouera également si la liste contient des éléments en double. Dans ce cas, quelque chose comme ça peut être plus approprié:

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
la source
1
Ce dont j'avais besoin était: Lorsque la boucle traverse son dernier élément: foreach (résultat de l'élément dans Model.Results) {if (result == Model.Results.Last ()) {<div> last </div>; } Il semble que vous vouliez à peu près la même chose.
mésaventure du
10
Votre code itérera deux fois dans toute la collection - mauvais si la collection n'est pas petite. Voir cette réponse.
Shimmy Weitzhandler
54
Cela ne fonctionne pas vraiment si vous avez des doublons dans votre collection. Par exemple, si vous travaillez avec une collection de chaînes et qu'il y a des doublons, ce code "différent avec le dernier élément" s'exécutera pour chaque occurrence du dernier élément de la liste.
muttley91
7
Cette réponse est ancienne, mais pour les autres personnes qui consultent cette réponse, vous pouvez obtenir le dernier élément et vous assurer de ne pas avoir à parcourir les éléments en utilisant: Item last = Model.Results [Model.Results.Count - 1] The count La propriété d'une liste ne nécessite pas de boucle. Si vous avez des doublons dans votre liste, utilisez simplement une variable d'itérateur dans une boucle for. Les boucles anciennes classiques ne sont pas mauvaises.
Michael Harris
Je suggère d'utiliser var last = Model.Result[Model.Result.Count - 1];plus rapidement que d'utiliserLast()
Tân
184

Que diriez-vous d'une bonne boucle à l'ancienne?

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

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

Ou en utilisant Linq et foreach:

foreach (Item result in Model.Results)   
{   
     if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
             // this is the last item
     }
}
Fiona - myaccessible.website
la source
14
Tant de personnes pensent trop à un problème simple comme celui-ci, alors que la boucle for est parfaitement capable de le faire déjà. : \
Andrew Hoffman
La solution Linq est mon préféré absolu! Merci pour le partage
mecographe
C'est la réponse la plus appropriée que celle acceptée.
Ratul
Remarque pour quiconque souhaite utiliser la solution LINQ sur une collection de chaînes (ou types de valeurs): Cela ne fonctionnera généralement pas car la comparaison == échouera si la dernière chaîne de la liste apparaît également plus tôt dans la liste. Cela ne fonctionnerait que si vous travaillez avec une liste garantie de ne pas avoir de chaînes en double.
Tawab Wakil
Malheureusement, vous ne pouvez pas utiliser cette solution intelligente si Model.Resultsc'est le cas IEnumerable. Vous pouvez appeler Count()avant la boucle mais cela peut provoquer l'itération complète de la séquence.
Luca Cremonesi
42

L'utilisation Last()sur certains types passera en boucle dans toute la collection!
Ce qui signifie que si vous faites un foreachappel Last()et que vous avez bouclé deux fois! que vous aimeriez certainement éviter dans les grandes collections.

La solution consiste alors à utiliser une do whileboucle:

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

Donc, à moins que le type de collection soit de type, IList<T>la Last()fonction itérera à travers tous les éléments de collection.

Tester

Si votre collection fournit un accès aléatoire (par exemple des outils IList<T>), vous pouvez également vérifier votre article comme suit.

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps
Shimmy Weitzhandler
la source
1
Êtes-vous sûr que l'énumérateur a besoin d'une usingdéclaration? Je pensais que cela n'était nécessaire que si un objet gère les ressources du système d'exploitation, mais pas pour les structures de données gérées.
Kitten accroupi le
IEnumerator n'implémente pas IDisposable, donc la ligne avec using avec déclenche une erreur de temps de compilation! +1 pour la solution, la plupart du temps, nous ne pouvons pas simplement utiliser un pour au lieu de foreach, car les éléments de collections énumérables calculent au moment de l'exécution ou la séquence ne prend pas en charge l'accès aléatoire.
Saleh
1
Le générique le fait.
Shimmy Weitzhandler
40

Comme Chris le montre, Linq fonctionnera; utilisez simplement Last () pour obtenir une référence à la dernière dans l'énumérable, et tant que vous ne travaillez pas avec cette référence, faites votre code normal, mais si vous travaillez avec cette référence, faites votre chose supplémentaire. Son inconvénient est qu'il sera toujours de complexité O (N).

Vous pouvez à la place utiliser Count () (qui est O (1) si IEnumerable est également un ICollection; cela est vrai pour la plupart des IEnumerables intégrés courants), et hybrider votre foreach avec un compteur:

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

  }
}
Gabriel Tiburcio
la source
Bonjour, celle-ci est la meilleure approche à ce jour! Simple et précis. Une approche programmeur-machiniste, une. Pourquoi ne choisissons-nous pas et donnons-nous de plus en plus à celui-ci!
Hanny Setiawan
1
Le dernier élément ne doit être trouvé qu'une seule fois ( promouvoir la mémorisation ) avant le foreachblocage. Comme ceci: var lastItem = objList.LastOrDeafault();. Ensuite , à l'intérieur de la foreachboucle , vous pouvez vérifier la façon suivante : f (item.Equals(lastItem)) { ... }. Dans votre réponse originale, l' objList.LastOrDefault()itération sur la collection à chaque itération "foreach" (la complexité polinomiale est impliquée ).
AlexMelw
Mauvaise réponse. complexité n ^ 2 au lieu de n.
Shimmy Weitzhandler
11

Comme l'a souligné Shimmy, l'utilisation de Last () peut être un problème de performances, par exemple si votre collection est le résultat en direct d'une expression LINQ. Pour éviter plusieurs itérations, vous pouvez utiliser une méthode d'extension "ForEach" comme celle-ci:

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

La méthode d'extension ressemble à ceci (en bonus supplémentaire, elle vous indiquera également l'index et si vous regardez le premier élément):

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
la source
9

En améliorant encore la réponse de Daniel Wolf , vous pouvez vous empiler sur une autre IEnumerablepour éviter plusieurs itérations et lambdas tels que:

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'implémentation de la méthode d'extension:

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
la source
1
L'autre réponse n'itère pas la source plusieurs fois, donc ce n'est pas un problème que vous résolvez. Vous avez en effet autorisé l'utilisation de foreach, ce qui est une amélioration.
Servy
1
@Servy, je veux dire cela. Outre l'itération unique de la réponse originale, j'évite les lambdas.
Fabricio Godoy
7

L'implémentation de l'itérateur ne fournit pas cela. Votre collection peut être une IListqui est accessible via un index dans O (1). Dans ce cas, vous pouvez utiliser une forboucle normale :

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

Si vous connaissez le nombre, mais ne pouvez pas y accéder via des indices (donc le résultat est un ICollection), vous pouvez vous compter en incrémentant un idans le foreachcorps du et en le comparant à la longueur.

Tout cela n'est pas parfaitement élégant. La solution de Chris est peut-être la meilleure que j'ai vue jusqu'à présent.

Matthias Meid
la source
En comparant les performances de votre compteur dans l'idée foreach vs la solution de Chris, je me demande ce qui coûterait plus cher - un seul appel Last (), ou la somme de toutes les opérations d'incrémentation ajoutées. Je soupçonne que ce serait proche.
TTT du
6

Qu'en est-il de l'approche peu plus 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
la source
2
Je ne sais pas pourquoi quelqu'un a voté contre. Ceci est parfaitement acceptable étant donné que vous effectuez déjà une foreach et que vous encourez le coût de o (n).
arviman
2
Malgré le fait que la réponse soit parfaite pour trouver le dernier élément, elle ne convient pas à l'état de l'OP " ..., déterminez quelle est la dernière itération de la boucle ". Ainsi, vous n'êtes pas en mesure de déterminer que la dernière itération est en fait la dernière, et, par conséquent, vous ne pouvez pas la gérer différemment ou même l'ignorer. C'est la raison pour laquelle quelqu'un vous a déçu. @arviman vous étiez si curieux à ce sujet.
AlexMelw
1
Vous avez raison, je l'ai totalement raté @ Andrey-WD. Je suppose que la solution à résoudre est d'appeler "last" une fois avant la boucle (ne peut pas le faire à l'intérieur de la boucle car ce serait O (N ^ 2) et ensuite vérifier si la référence correspond.)
arviman
5

La meilleure approche serait probablement d'exécuter cette étape après la boucle: par exemple

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

//Post execution logic

Ou si vous devez faire quelque chose pour le dernier résultat

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

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

//Execute logic on lastItem here
Dustin Hodges
la source
3

La réponse acceptée ne fonctionnera pas pour les doublons de la collection. Si vous êtes défini sur le foreach, vous pouvez simplement ajouter vos propres variables d'indexation.

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
la source
2

en utilisant Linq et 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
la source
1
cela ne fonctionnera que si la liste / collection a des valeurs uniques.
melleck
1

".Last ()" n'a pas fonctionné pour moi, j'ai donc dû faire quelque chose comme ceci:

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
la source
1

En faisant quelques petits ajustements à l'excellent code de Jon Skeet, vous pouvez même le rendre plus intelligent en autorisant l'accès à l'élément précédent et suivant. Bien sûr, cela signifie que vous devrez lire à l'avance 1 élément dans la mise en œuvre. Pour des raisons de performances, l'élément précédent et l'élément suivant sont uniquement conservés pour l'élément d'itération en cours. Ça va comme ça:

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
la source
1

Comment convertir foreachpour réagir au dernier élément:

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
la source
1

Il suffit de stocker la valeur précédente et de travailler avec elle dans la boucle. Ensuite, à la fin, la valeur «précédente» sera le dernier élément, vous permettant de le gérer différemment. Aucun comptage ou bibliothèque spéciale requise.

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
la source
1

Vous pouvez simplement utiliser une boucle for et il n'est pas nécessaire d'ajouter un supplément ifà l'intérieur du forcorps:

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

Le -1dans l' forétat se charge de sauter le dernier élément.

Alisson
la source
Le -1 dans la boucle for ne s'occupe pas de sauter le dernier élément. Vous obtiendrez une IndexOutOfRangeException si vous n'incluez pas le -1.
Jaa H
0

Pour faire quelque chose de plus pour chaque élément, sauf pour le dernier, une approche basée sur les fonctions peut être utilisée.

delegate void DInner ();

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

Cette approche présente des inconvénients apparents: moins de clarté de code pour les cas plus complexes. Appeler des délégués pourrait ne pas être très efficace. Le dépannage n'est peut-être pas assez facile. Le bon côté - le codage est amusant!

Cela dit, je suggérerais d'utiliser des boucles simples pour les cas triviaux, si vous savez que le décompte de votre collection n'est pas terriblement lent.

dmitry
la source
0

Une autre façon, que je n'ai pas vue publiée, est d'utiliser une file d'attente. C'est analogue à un moyen d'implémenter une méthode SkipLast () sans itérer plus que nécessaire. De cette façon, vous pourrez également le faire sur un nombre illimité de derniers éléments.

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

Pour appeler cela, vous devez procéder comme suit:

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

Vous pouvez créer une méthode d'extension spécialement dédiée à cela:

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

et vous pouvez l'utiliser comme ceci:

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

Sur la base de la réponse de @ Shimmy, j'ai créé une méthode d'extension qui est la solution que tout le monde veut. Il est simple, facile à utiliser et ne parcourt la collection qu'une seule fois.

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

Cela fonctionne sur tout IEnumerable<T>. L'utilisation ressemble à ceci:

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

La sortie ressemble à:

1,
2,
3,
4,
5

De plus, vous pouvez en faire une Selectméthode de style. Ensuite, réutilisez cette extension dans le ForEach. Ce code ressemble à ceci:

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
la source
-1

Nous pouvons vérifier le dernier élément en boucle.

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

la source
(!) Peu importe à quel point votre code est bon ou mauvais. Sans explication, il n'a généralement aucune valeur.
AlexMelw
De plus, il semble bien trop complexe.
mecographe
-3

Vous pouvez faire comme ça:

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