Проведіть цикл, визначте, яка є остання ітерація циклу


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

1
Що мені потрібно було: Коли цикл переходить через останній елемент: foreach (Результат елемента в Model.Results) {if (result == Model.Results.Last ()) {<div> last </div>; } Здається, ви майже означали те саме.
mishap

10
Код буде повторюватися двічі через всю колекцію - погано, якщо колекція не мала. Дивіться цю відповідь.
Шиммі Вайцхандлер

54
Це насправді не працює, якщо у вашій колекції є дублікати. Наприклад, якщо ви працюєте з колекцією рядків, і є дублікати, код "відрізняється від останнього елемента" буде виконуватися для кожного появи останнього елемента в списку.
muttley91

7
Ця відповідь стара, але для інших, хто дивиться на цю відповідь, ви можете отримати останній елемент і переконатися, що вам не доведеться перебирати елементи, використовуючи: Item last = Model.Results [Model.Results.Count - 1] Кількість властивість списку не вимагає циклічного циклу. Якщо у вашому списку є дублікати, просто використовуйте змінну ітератора в циклі a. Звичайні старі для петель непогані.
Майкл Гарріс

Я пропоную , використовуючи 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
     }
}

14
Так багато ppl переосмислює просту подібну проблему, як ця, коли цикл for цілком здатний це зробити вже. : \
Ендрю Гофман

Рішення Linq - мій абсолютний фаворит! Дякую за те, що поділився
mecograph

Це більш відповідна відповідь, ніж прийнята.
Ратул

Зауважте всім, хто бажає використовувати рішення LINQ для колекції рядків (або типів значень): зазвичай це не буде працювати, оскільки порівняння == не вдасться, якщо останній рядок у списку також з’явиться раніше у списку. Він буде працювати лише в тому випадку, якщо ви працюєте зі списком, який гарантовано не має дублюючих рядків.
Tawab Wakil

На жаль, ви не можете використовувати це розумне рішення, якщо 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, тому рядок використання з підвищенням помилки часу компіляції! +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
}

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()б повторення колекції під час кожної ітерації "передбачення" (в цьому полягає поліноміальна складність ).
AlexMelw

Погана відповідь. n ^ 2 складність замість n.
Шиммі Вайцхандлер

11

Як зазначив Shimmy, використання 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, що є вдосконаленням.
Сервіс

1
@ Серві я маю на увазі це. Крім одиничної ітерації від оригінальної відповіді, я уникаю лямбдів.
Fabricio Godoy

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 тілі «s і порівнюючи його з довжиною.

Все це не зовсім елегантно. Рішення Кріса може бути найкращим, що я бачив досі.


Порівнюючи продуктивність вашого лічильника в рамках ідеї 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
Я не знаю, чому хтось зголосив вас. Це цілком прийнятно, враховуючи, що ви вже виконуєте передбачення і несете витрати на 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++;
}

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


1
це працюватиме лише тоді, коли список / колекція має унікальні значення.
Меллек

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

1

Зробивши невеликі корективи у відмінному коді Джона Скіта, ви навіть можете зробити його розумнішим, дозволивши доступ до попереднього та наступного пункту. Звичайно, це означає, що вам доведеться заздалегідь прочитати 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);
}

1

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

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

У -1такому forстані піклується про пропуск останнього пункту.


Цикл -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
    }
}

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

Сказавши це, я б запропонував використовувати просту для циклів у тривіальних випадках, якщо ви знаєте, що кількість вашої колекції не дуже страшна.


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

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

Також здається, що це занадто інженерно.
мекограф

-3

Ви можете зробити так:

foreach (DataGridViewRow dgr in product_list.Rows)
{
    if (dgr.Index == dgr.DataGridView.RowCount - 1)
    {
        //do something
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.