Цикл Foreach, определите, какая последняя итерация цикла

233

У меня есть foreachцикл, и мне нужно выполнить некоторую логику, когда последний элемент выбран из List, например:

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

Могу ли я узнать, какой цикл является последним без использования цикла и счетчиков?

несчастье
источник
1
Посмотрите на мой ответ здесь, чтобы найти решение, которое я опубликовал для соответствующего вопроса.
Брайан Гидеон

Ответы:

294

Если вам просто нужно что-то сделать с последним элементом (в отличие от чего-то другого с последним элементом, то здесь поможет LINQ:

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

Если вам нужно сделать что-то другое с последним элементом, вам нужно что-то вроде:

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

Хотя вам, вероятно, нужно написать собственный компаратор, чтобы убедиться, что вы можете сказать, что элемент совпадает с элементом, возвращаемым Last().

Этот подход следует использовать с осторожностью, так как, Lastвозможно, придется повторять всю коллекцию. Хотя это не может быть проблемой для небольших коллекций, но если она станет большой, это может повлиять на производительность. Также произойдет сбой, если список содержит повторяющиеся элементы. В этом случае что-то вроде этого может быть более подходящим:

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
источник
1
Мне нужно было следующее: когда цикл проходит через последний элемент: foreach (результат элемента в Model.Results) {if (result == Model.Results.Last ()) {<div> last </ div>; } Похоже, вы имели в виду то же самое.
неудача
10
Ваш код будет повторяться дважды по всей коллекции - плохо, если коллекция не маленькая. Смотрите этот ответ.
Shimmy Weitzhandler
54
Это действительно не работает, если у вас есть дубликаты в вашей коллекции. Например, если вы работаете с набором строк, и есть какие-либо дубликаты, то этот код «отличается от последнего элемента» будет выполняться для каждого вхождения последнего элемента в списке.
muttley91
7
Этот ответ старый, но для тех, кто ищет этот ответ, вы можете получить последний элемент и убедиться, что вам не нужно циклически проходить через элементы, используя: Item last = Model.Results [Model.Results.Count - 1] Количество Свойство списка не требует зацикливания. Если в вашем списке есть дубликаты, просто используйте переменную итератора в цикле for. Обычные старые петли не плохие.
Майкл Харрис
Я предлагаю использовать var last = Model.Result[Model.Result.Count - 1];для более быстрого, чем использованиеLast()
Tân
184

Как насчет старой доброй петли?

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

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

Или используя Linq и foreach:

foreach (Item result in Model.Results)   
{   
     if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
             // this is the last item
     }
}
Фиона - myaccessible.website
источник
14
Так много людей задумывались над такой простой проблемой, когда цикл for уже вполне способен это сделать. : \
Эндрю Хоффман
Решение Linq - мой самый любимый! Спасибо за обмен
mecograph
Это более подходящий ответ, чем принятый.
Ратул
Примечание для всех, кто хочет использовать решение LINQ для набора строк (или типов значений): обычно оно не будет работать, потому что сравнение == не будет выполнено, если последняя строка в списке также появится раньше в списке. Это будет работать только в том случае, если вы работаете со списком, в котором гарантированно отсутствуют повторяющиеся строки.
Таваб Вакиль
К сожалению, вы не можете использовать это умное решение, если Model.Resultsесть IEnumerable. Вы можете вызвать Count()до цикла, но это может привести к полной итерации последовательности.
Лука Кремонези
42

Использование Last()определенных типов будет проходить через всю коллекцию!
Это значит, что если вы делаете foreachколл и коллируете Last(), вы зациклились дважды! Я уверен, что вы хотели бы избежать в больших коллекциях.

Тогда решение состоит в том, чтобы использовать do whileцикл:

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

Таким образом , если тип коллекции не имеет типа функция будет перебирать через все элементы коллекции.IList<T>Last()

Тест

Если ваша коллекция предоставляет произвольный доступ (например, орудия IList<T>), вы также можете проверить свой предмет следующим образом.

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps
Шимми Вайцхандлер
источник
1
Вы уверены, что перечислителю нужно usingутверждение? Я думал, что это необходимо, только если объект обрабатывает ресурсы операционной системы, но не для управляемых структур данных.
Крадущийся котенок
IEnumerator не реализует IDisposable, поэтому строка с использованием with вызывает ошибку времени компиляции! +1 для решения, в большинстве случаев мы не можем просто использовать for вместо foreach, потому что перечисляемые элементы коллекций вычисляются во время выполнения или последовательность не поддерживает произвольный доступ.
Салех
1
Родовые один делает.
Шимми Вайцхандлер
40

Как показывает Крис, Линк будет работать; просто используйте Last (), чтобы получить ссылку на последнюю в перечислимом, и, если вы не работаете с этой ссылкой, делайте обычный код, но если вы работаете с этой ссылкой, делайте свою дополнительную вещь. Недостатком является то, что это всегда будет O (N) -сложность.

Вместо этого вы можете использовать Count () (то есть O (1), если IEnumerable также является ICollection; это верно для большинства распространенных встроенных IEnumerables), и гибридизировать ваш foreach со счетчиком:

var i=0;
var count = Model.Results.Count();
foreach (Item result in Model.Results)
{
    if (++i == count) //this is the last item
}
Keiths
источник
22
foreach (var item in objList)
{
  if(objList.LastOrDefault().Equals(item))
  {

  }
}
Габриэль Тибурсио
источник
Здравствуйте, это лучший подход на сегодняшний день! Просто и по существу. Подход программиста, один. Почему бы нам не выбрать и не дать этому +1 еще и еще!
Hanny Setiawan
1
Последний элемент должен быть найден только один раз ( содействовать запоминанию ) перед foreachблокировкой. Как это: var lastItem = objList.LastOrDeafault();. Затем с внутренней стороны foreachпетли вы можете проверить это следующим образом: f (item.Equals(lastItem)) { ... }. В вашем исходном ответе objList.LastOrDefault()будет проходить итерацию по коллекции на каждой итерации "foreach" ( сложность полинома ).
AlexMelw
Плохой ответ n ^ 2 сложность вместо n.
Шимми Вайцхандлер
11

Как указал Шимми, использование Last () может быть проблемой производительности, например, если ваша коллекция является живым результатом выражения LINQ. Чтобы предотвратить несколько итераций, вы можете использовать метод расширения «ForEach», например:

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

Метод расширения выглядит следующим образом (в качестве дополнительного бонуса он также сообщит вам индекс и, если вы смотрите на первый элемент):

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

Улучшив ответ Даниэля Вольфа, вы можете использовать другую, IEnumerableчтобы избежать нескольких итераций и лямбд, таких как:

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

Реализация метода расширения:

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
Другой ответ не повторяет источник несколько раз, так что это не проблема, которую вы исправляете. Вы действительно разрешили использовать foreach, что является улучшением.
Servy
1
@ Служу, я имею в виду Помимо одной итерации от оригинального ответа я избегаю лямбды.
Фабрисио Годой
7

Реализация итератора не обеспечивает этого. Ваша коллекция может быть IListдоступной через индекс в O (1). В этом случае вы можете использовать обычный for-loop:

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

Если вы знаете количество, но не можете получить доступ с помощью индексов (таким образом, результатом является ICollection), вы можете подсчитать себя, увеличив значение iв foreachтеле и сравнив его с длиной.

Все это не совсем элегантно. Решение Криса может быть самым хорошим, которое я видел до сих пор.

Матиас Мейд
источник
При сравнении производительности вашего счетчика в рамках идеи foreach с решением Криса, мне интересно, что обойдется дороже - один вызов Last () или сумма всех добавленных операций приращения. Я подозреваю, что это будет близко.
TTT
6

Как насчет немного более простого подхода.

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
Я не знаю, почему кто-то проголосовал против вас. Это вполне приемлемо, учитывая, что вы уже выполняете foreach и несете стоимость o (n).
arviman
2
Несмотря на то, что ответ идеально подходит для определения последнего элемента, он не соответствует условию ОП " ... определить, какая последняя итерация цикла ". Таким образом, вы не можете определить, что последняя итерация на самом деле является последней, и, таким образом, вы не можете обрабатывать ее по-другому или даже игнорировать ее. Вот почему кто-то отрицал тебя. @arviman тебе было так любопытно.
AlexMelw
1
Вы правы, я полностью пропустил это @ Andrey-WD. Я думаю, что решение для исправления состоит в том, чтобы вызвать «последний» один раз перед циклом (не может сделать это внутри цикла, как это будет O (N ^ 2), а затем проверить, соответствует ли ссылка.
arviman
5

Лучшим подходом, вероятно, будет просто выполнить этот шаг после цикла: например,

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

//Post execution logic

Или если нужно что-то сделать до последнего результата

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

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

//Execute logic on lastItem here
Дастин Ходжес
источник
3

Принятый ответ не будет работать для дубликатов в коллекции. Если вы настроены на foreach, вы можете просто добавить свои собственные индексные переменные.

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
источник
2

используя Linq и 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
источник
1
это будет работать, только если список / коллекция имеет уникальные значения.
Melleck
1

«.Last ()» не работал для меня, поэтому я должен был сделать что-то вроде этого:

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
источник
1

Сделав небольшие изменения в превосходном коде Jon Skeet, вы даже можете сделать его умнее, предоставив доступ к предыдущему и следующему элементу. Конечно, это означает, что вам придется прочитать 1 пункт в реализации. По соображениям производительности предыдущий и следующий элемент сохраняются только для текущего элемента итерации. Это выглядит так:

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

Как конвертировать, foreachчтобы отреагировать на последний элемент:

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

Просто сохраните предыдущее значение и работайте с ним внутри цикла. Тогда в конце «предыдущее» значение будет последним элементом, что позволит вам обрабатывать его по-другому. Нет подсчета или специальных библиотек не требуется.

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
источник
1

Вы можете просто использовать цикл for, и нет необходимости добавлять дополнительные ifвнутри forтела:

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

Состояние -1in forпропускает последний элемент.

Alisson
источник
-1 в цикле for не заботится о пропуске последнего элемента. Вы бы получили исключение IndexOutOfRangeException, если бы вы не указали -1.
Jaa H
0

Чтобы сделать что-то дополнительное для каждого элемента, кроме последнего, можно использовать подход на основе функций.

delegate void DInner ();

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

Этот подход имеет очевидные недостатки: меньшая ясность кода для более сложных случаев. Вызов делегатов может быть не очень эффективным. Устранение неполадок может быть не совсем простым. Яркая сторона - кодирование это весело!

Сказав это, я бы предложил использовать обычные циклы for в тривиальных случаях, если вы знаете, что счет вашей коллекции не очень медленный.

дмитрий
источник
0

Другой способ, который я не видел размещенным, состоит в том, чтобы использовать Очередь. Это аналог способа реализации метода SkipLast () без итерации больше, чем необходимо. Этот способ также позволит вам сделать это на любом количестве последних предметов.

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

Чтобы вызвать это, вы должны сделать следующее:

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

Вы можете сделать метод расширения, специально предназначенный для этого:

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

и вы можете использовать это так:

foreach (Item result in Model.Results)
{
    if(Model.Results.IsLast(result))
    {
        //do something in the code
    }
}
А. Морель
источник
0

Основываясь на ответе @ Shimmy, я создал метод расширения, который является решением, которое каждый хочет. Он прост, удобен в использовании и проходит через коллекцию только один раз.

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

Это работает на любом IEnumerable<T>. Использование выглядит так:

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

Вывод выглядит так:

1,
2,
3,
4,
5

Кроме того, вы можете превратить это в Selectметод стиля. Затем повторно используйте это расширение в ForEach. Этот код выглядит так:

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

Мы можем проверить последний элемент в цикле.

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

источник
(!) Независимо от того, насколько хорош или плох ваш код. Без объяснения это обычно не имеет значения.
AlexMelw
Кроме того, это кажется слишком сложным.
mecograph
-3

Вы можете сделать так:

foreach (DataGridViewRow dgr in product_list.Rows)
{
    if (dgr.Index == dgr.DataGridView.RowCount - 1)
    {
        //do something
    }
}
Sheharyar
источник