Vòng lặp Foreach, xác định đó là lần lặp cuối cùng của vòng lặp


233

Tôi có một foreachvòng lặp và cần thực thi một số logic khi mục cuối cùng được chọn từ List, ví dụ:

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

Tôi có thể biết vòng lặp nào là cuối cùng mà không sử dụng vòng lặp và bộ đếm không?


1
Hãy xem câu trả lời của tôi ở đây cho một giải pháp tôi đã đăng cho một câu hỏi liên quan.
Brian Gideon

Câu trả lời:


293

Nếu bạn chỉ cần làm một cái gì đó với phần tử cuối cùng (trái ngược với một cái gì đó khác với phần tử cuối cùng thì sử dụng LINQ sẽ giúp ích ở đây:

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

Nếu bạn cần làm gì đó khác với phần tử cuối cùng thì bạn cần một cái gì đó như:

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

Mặc dù bạn có thể cần phải viết một bộ so sánh tùy chỉnh để đảm bảo rằng bạn có thể nói rằng mục đó giống với mục được trả về Last().

Cách tiếp cận này nên được sử dụng một cách thận trọng vì Lastcó thể phải lặp đi lặp lại qua bộ sưu tập. Mặc dù điều này có thể không phải là vấn đề đối với các bộ sưu tập nhỏ, nhưng nếu nó lớn, nó có thể có ý nghĩa về hiệu suất. Nó cũng sẽ thất bại nếu danh sách chứa các mục trùng lặp. Trong trường hợp này, một cái gì đó như thế này có thể phù hợp hơn:

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
Điều tôi cần là: Khi vòng lặp đi qua mục cuối cùng của nó: foreach (Mục kết quả trong Model.Results) {if (result == Model.Results.Last ()) {<div> last </ div>; } Có vẻ như bạn khá nhiều ý nghĩa tương tự.
rủi ro

10
Mã của bạn sẽ lặp lại hai lần cho toàn bộ bộ sưu tập - thật tệ nếu bộ sưu tập không nhỏ. Xem câu trả lời này .
Shimmy Weitzhandler

54
Điều này không thực sự hoạt động nếu bạn có bản sao trong bộ sưu tập của mình. Ví dụ: nếu bạn đang làm việc với một tập hợp các chuỗi và có bất kỳ sự trùng lặp nào, thì mã "khác với mục cuối" sẽ thực thi cho mỗi lần xuất hiện của mục cuối cùng trong danh sách.
muttley91

7
Câu trả lời này đã cũ, nhưng đối với những người khác đang xem câu trả lời này, bạn có thể lấy phần tử cuối cùng và đảm bảo bạn không phải lặp qua các phần tử bằng cách sử dụng: Item last = Model.Results [Model.Results.Count - 1] Đếm tài sản của một danh sách không yêu cầu lặp. Nếu bạn có các bản sao trong danh sách của mình, thì chỉ cần sử dụng biến lặp trong vòng lặp for. Thường xuyên cũ cho các vòng lặp không phải là xấu.
Michael Harris

Tôi đề nghị sử dụng var last = Model.Result[Model.Result.Count - 1];để nhanh hơn sử dụngLast()
Tân

184

Làm thế nào về một vòng lặp cũ tốt cho vòng lặp?

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

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

Hoặc sử dụng Linq và foreach:

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

14
Vì vậy, nhiều ppl đã xem xét một vấn đề đơn giản như thế này, khi vòng lặp for hoàn toàn có khả năng thực hiện nó. : \
Andrew Hoffman

Giải pháp Linq là yêu thích tuyệt đối của tôi! Cảm ơn bạn đã chia sẻ
mecograph

Đây là câu trả lời thích hợp hơn câu trả lời được chấp nhận.
Ratul

Lưu ý cho bất kỳ ai muốn sử dụng giải pháp LINQ trên bộ sưu tập các chuỗi (hoặc loại giá trị): Nó thường không hoạt động vì so sánh == sẽ thất bại nếu chuỗi cuối cùng trong danh sách cũng xuất hiện sớm hơn trong danh sách. Nó chỉ hoạt động nếu bạn đang làm việc với một danh sách được đảm bảo không có chuỗi trùng lặp.
Tawab Wakil

Thật không may, bạn không thể sử dụng giải pháp thông minh này nếu Model.Resultslà một IEnumerable. Bạn có thể gọi Count()trước vòng lặp nhưng điều đó có thể gây ra sự lặp lại đầy đủ của chuỗi.
Luca Cremonesi

42

Sử dụng Last()trên một số loại nhất định sẽ lặp qua toàn bộ bộ sưu tập!
Có nghĩa là nếu bạn thực hiện foreachvà gọi Last(), bạn đã lặp lại hai lần! mà tôi chắc chắn bạn muốn tránh trong các bộ sưu tập lớn.

Sau đó, giải pháp là sử dụng một do whilevòng lặp:

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

Vì vậy, trừ khi kiểu tập hợp là kiểu IList<T>, Last()hàm sẽ lặp qua tất cả các phần tử tập hợp.

Kiểm tra

Nếu bộ sưu tập của bạn cung cấp quyền truy cập ngẫu nhiên (ví dụ: thực hiện IList<T>), bạn cũng có thể kiểm tra mục của mình như sau.

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

1
Bạn có chắc chắn rằng điều tra viên cần một usingtuyên bố? Tôi nghĩ rằng điều đó chỉ cần thiết nếu một đối tượng xử lý tài nguyên hệ điều hành, nhưng không phải cho các cấu trúc dữ liệu được quản lý.
Ngọa mèo

IEnumerator không triển khai IDis Dùng một lần, do đó, dòng sử dụng với lỗi tăng thời gian biên dịch! +1 cho giải pháp, hầu hết thời gian chúng ta không thể chỉ sử dụng một thay cho foreach, bởi vì vô số các mục bộ sưu tập tính toán trong thời gian chạy hoặc chuỗi không hỗ trợ truy cập ngẫu nhiên.
Saleh

1
Một cái chung chung nào.
Shimmy Weitzhandler

40

Như Chris cho thấy, Linq sẽ làm việc; chỉ cần sử dụng Last () để có được một tham chiếu đến cái cuối cùng trong số vô số, và miễn là bạn không làm việc với tham chiếu đó thì hãy làm mã bình thường của bạn, nhưng nếu bạn đang làm việc với tham chiếu đó thì hãy làm thêm. Nhược điểm của nó là nó sẽ luôn luôn là tính linh hoạt O (N).

Thay vào đó, bạn có thể sử dụng Count () (là O (1) nếu IEnumerable cũng là một ICollection; điều này đúng với hầu hết các IEnumerables tích hợp phổ biến) và kết hợp foreach của bạn với bộ đếm:

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

  }
}

Xin chào, đây là cách tiếp cận tốt nhất cho đến nay! Ngắn gọn và đúng trọng tâm. Một cách tiếp cận lập trình-điều, một. Tại sao chúng ta không chọn và cung cấp cho +1 này ngày càng nhiều!
Hanny Setiawan

1
Mục cuối cùng chỉ được tìm thấy một lần ( Thúc đẩy ghi nhớ ) trước khi foreachchặn. Như thế này : var lastItem = objList.LastOrDeafault();. Sau đó, từ bên trong của foreachvòng lặp, bạn có thể kiểm tra nó theo cách này : f (item.Equals(lastItem)) { ... }. Trong câu trả lời ban đầu của bạn, việc objList.LastOrDefault()lặp đi lặp lại trên bộ sưu tập ở mỗi lần lặp "foreach" ( Sự phức tạp của Polinomial có liên quan ).
AlexMelw

Câu trả lời không hay. n ^ 2 độ phức tạp thay vì n.
Shimmy Weitzhandler

11

Như Shimmy đã chỉ ra, sử dụng Last () có thể là một vấn đề về hiệu năng, ví dụ nếu bộ sưu tập của bạn là kết quả trực tiếp của biểu thức LINQ. Để ngăn chặn nhiều lần lặp, bạn có thể sử dụng phương thức mở rộng "ForEach" như thế này:

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

Phương thức tiện ích mở rộng trông như thế này (như một phần thưởng bổ sung, nó cũng sẽ cho bạn biết chỉ mục và nếu bạn đang xem phần tử đầu tiên):

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

Cải thiện câu trả lời của Daniel Wolf hơn nữa, bạn có thể xếp chồng lên nhau IEnumerableđể tránh nhiều lần lặp và lambdas như:

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

Việc thực hiện phương pháp mở rộng:

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
Câu trả lời khác không lặp lại nguồn nhiều lần, vì vậy đó không phải là vấn đề bạn đang sửa. Bạn thực sự đã cho phép sử dụng foreach, đó là một cải tiến.
Phục vụ

1
@Servy Ý tôi là thế. Bên cạnh việc lặp lại từ câu trả lời ban đầu, tôi đang tránh lambdas.
Fabricio Godoy

7

Việc thực hiện lặp không cung cấp điều đó. Bộ sưu tập của bạn có thể là một bộ sưu tập có thể IListtruy cập thông qua một chỉ mục trong O (1). Trong trường hợp đó, bạn có thể sử dụng một for-loop bình thường :

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

Nếu bạn biết số đếm, nhưng không thể truy cập thông qua các chỉ số (do đó, kết quả là một ICollection), bạn có thể tự đếm bằng cách tăng một số itrong foreachcơ thể và so sánh nó với độ dài.

Tất cả điều này không hoàn hảo thanh lịch. Giải pháp của Chris có thể là tốt nhất tôi từng thấy cho đến nay.


Khi so sánh hiệu suất của bộ đếm của bạn trong ý tưởng foreach và giải pháp của Chris, tôi tự hỏi cái nào sẽ tốn nhiều tiền hơn - một cuộc gọi Last () duy nhất hoặc tổng của tất cả các hoạt động gia tăng được thêm vào. Tôi nghi ngờ nó sẽ gần gũi.
TTT

6

Những gì về cách tiếp cận đơn giản hơn.

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
Tôi không biết tại sao ai đó bỏ phiếu cho bạn. Điều này là hoàn toàn chấp nhận được khi bạn đang thực hiện một cuộc thảo luận và đang phát sinh chi phí o (n).
arviman

2
Mặc dù thực tế rằng câu trả lời là hoàn hảo để tìm ra mục cuối cùng, nhưng nó không phù hợp với điều kiện của OP " ..., xác định xem đó là lần lặp cuối cùng của vòng lặp ". Vì vậy, bạn không thể xác định rằng lần lặp cuối cùng thực sự là lần lặp cuối cùng, và do đó, bạn không thể xử lý nó theo cách khác hoặc thậm chí bỏ qua nó. Đó là lý do ai đó đã hạ bệ bạn. @arviman bạn đã rất tò mò về nó.
AlexMelw

1
Bạn nói đúng, tôi hoàn toàn nhớ nó @ Andrey-WD. Tôi nghĩ giải pháp để khắc phục là để gọi là "cuối cùng" một lần trước khi vòng lặp (không thể làm điều đó trong vòng lặp như nó sẽ là O (N ^ 2) và sau đó kiểm tra xem tài liệu tham khảo phù hợp với nó.
arviman

5

Cách tiếp cận tốt nhất có lẽ chỉ là thực hiện bước đó sau vòng lặp: vd

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

//Post execution logic

Hoặc nếu bạn cần làm gì đó cho kết quả cuối cùng

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

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

//Execute logic on lastItem here

3

Câu trả lời được chấp nhận sẽ không hoạt động cho các bản sao trong bộ sưu tập. Nếu bạn được đặt trên foreach, bạn chỉ có thể thêm (các) biến lập chỉ mục của riêng bạn.

int last = Model.Results.Count - 1;
int index = 0;
foreach (Item result in Model.Results)
{
    //Do Things

    if (index == last)
        //Do Things with the last result

    index++;
}

2

sử dụng Linq và 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
điều này sẽ chỉ hoạt động nếu danh sách / bộ sưu tập có các giá trị duy nhất.
melleck

1

".Last ()" không hoạt động với tôi, vì vậy tôi phải làm một cái gì đó như thế này:

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

Thực hiện một số điều chỉnh nhỏ cho mã xuất sắc của Jon Skeet, bạn thậm chí có thể làm cho nó thông minh hơn bằng cách cho phép truy cập vào mục trước và mục tiếp theo. Tất nhiên, điều này có nghĩa là bạn sẽ phải đọc trước 1 mục trong quá trình thực hiện. Vì lý do hiệu suất, mục trước và mục tiếp theo chỉ được giữ lại cho mục lặp hiện tại. Nó như thế này:

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

Cách chuyển đổi foreachđể phản ứng với phần tử cuối cùng:

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

Chỉ cần lưu trữ giá trị trước đó và làm việc với nó bên trong vòng lặp. Sau đó, ở cuối giá trị 'trước' sẽ là mục cuối cùng, cho phép bạn xử lý nó theo cách khác. Không cần đếm hoặc thư viện đặc biệt cần thiết.

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

Bạn chỉ có thể sử dụng một vòng lặp for và không cần thêm một phần ifbên trong forcơ thể:

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

Các -1trong forđiều kiện chăm sóc bỏ qua mục cuối cùng.


-1 trong vòng lặp for không quan tâm đến việc bỏ qua mục cuối cùng. Bạn sẽ nhận được IndexOutOfRangeException nếu bạn không bao gồm -1.
Jaa H


0

Để làm một cái gì đó bổ sung cho mỗi phần tử ngoại trừ phần tử cuối cùng, phương pháp dựa trên chức năng có thể được sử dụng.

delegate void DInner ();

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

Cách tiếp cận này có nhược điểm rõ ràng: ít rõ ràng về mã cho các trường hợp phức tạp hơn. Gọi đại biểu có thể không hiệu quả lắm. Khắc phục sự cố có thể không hoàn toàn dễ dàng. Mặt sáng - mã hóa là niềm vui!

Có nói rằng, tôi sẽ đề nghị sử dụng đồng bằng cho các vòng lặp trong các trường hợp tầm thường, nếu bạn biết rằng số lượng bộ sưu tập của bạn không quá chậm.


0

Một cách khác, mà tôi không thấy được đăng, là sử dụng Hàng đợi. Nó tương tự như một cách để thực hiện phương thức SkipLast () mà không lặp lại nhiều hơn mức cần thiết. Cách này cũng sẽ cho phép bạn làm điều này trên bất kỳ số lượng mục cuối cùng.

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

Để gọi điều này, bạn sẽ làm như sau:

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

Bạn có thể tạo một phương thức mở rộng dành riêng cho việc này:

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

và bạn có thể sử dụng nó như thế này:

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

0

Dựa trên phản hồi của @ Shimmy, tôi đã tạo ra một phương thức mở rộng là giải pháp mà mọi người đều muốn. Nó đơn giản, dễ sử dụng và chỉ lặp qua bộ sưu tập một lần.

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

Điều này hoạt động trên bất kỳ IEnumerable<T>. Cách sử dụng trông như thế này:

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

Đầu ra trông như:

1,
2,
3,
4,
5

Ngoài ra, bạn có thể biến điều này thành một Selectphương thức kiểu. Sau đó, sử dụng lại phần mở rộng đó trong ForEach. Mã đó trông như thế này:

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

Chúng ta có thể kiểm tra mục cuối cùng trong vòng lặp.

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

(!) Cho dù mã của bạn tốt hay xấu như thế nào. Không có lời giải thích nó thường không có giá trị.
AlexMelw

Ngoài ra nó có vẻ quá thiết kế.
mecograph

-3

Bạn có thể làm như thế này:

foreach (DataGridViewRow dgr in product_list.Rows)
{
    if (dgr.Index == dgr.DataGridView.RowCount - 1)
    {
        //do something
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.