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
 }

for 루프와 카운터를 사용하지 않고 어떤 루프가 마지막인지 알 수 있습니까?


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>; } 거의 같은 의미 인 것 같습니다.
사고

10
전체 컬렉션을 통해 두 번 반복하여 코드를 작성합니다. 컬렉션이 작지 않으면 나쁩니다. 답변을 참조하십시오 .
Shimmy Weitzhandler

54
컬렉션에 복제본이 있으면 실제로 작동하지 않습니다. 예를 들어, 문자열 모음으로 작업하고 있고 중복 된 항목이 있으면 목록에서 마지막 항목이 나타날 때마다 "마지막 항목과 다른"코드가 실행됩니다.
muttley91

7
이 답변은 오래되었지만이 답변을보고있는 다른 사람들은 마지막 요소를 얻을 수 있으며 다음을 사용하여 요소를 반복 할 필요가 없습니다. Item last = Model.Results [Model.Results.Count-1] Count 리스트의 속성은 루핑을 요구하지 않습니다. 목록에 중복이 있으면 for 루프에서 반복자 변수를 사용하십시오. 규칙적인 이전 for 루프는 나쁘지 않습니다.
Michael Harris

사용 var last = Model.Result[Model.Result.Count - 1];하는 것보다 더 빨리 사용 하는 것이 좋습니다Last()
Tân

184

좋은 구식 for 루프는 어떻습니까?

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
for 루프가 이미 완벽하게 수행 할 수있을 때 많은 ppl이 이와 같은 간단한 문제를 지나치게 생각합니다. : \
Andrew Hoffman

Linq 솔루션은 제가 가장 좋아하는 것입니다! 공유 주셔서 감사
mecograph

이것은 허용되는 것보다 더 적절한 대답입니다.
Ratul

문자열 (또는 값 형식) 모음에서 LINQ 솔루션을 사용하려는 사람은 다음을 참고하십시오. 목록의 마지막 문자열이 목록의 앞부분에 있으면 == 비교가 실패하기 때문에 일반적으로 작동하지 않습니다. 중복 문자열이 없음을 보장하는 목록으로 작업하는 경우에만 작동합니다.
Tawab Wakil

불행히도이 똑똑한 솔루션을 사용할 수 없습니다 Model.Results입니다 IEnumerable. Count()루프 전에 호출 할 수 있지만 시퀀스가 ​​완전히 반복 될 수 있습니다.
Luca Cremonesi

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와 함께 사용하면 컴파일 시간 오류가 발생합니다! 열거 가능한 컬렉션 항목이 런타임에 계산되거나 시퀀스가 ​​무작위 액세스를 지원하지 않기 때문에 대부분의 경우 foreach 대신 단순히 for를 사용할 수 없습니다.
Saleh


40

Chris가 보여 주듯이 Linq는 일할 것입니다. Last ()를 사용하여 열거 가능한 마지막 항목에 대한 참조를 얻으십시오. 해당 참조로 작업하지 않는 한 일반 코드를 수행하지만 해당 참조로 작업하는 경우 추가 작업을 수행하십시오. 단점은 항상 O (N) 복잡성이라는 것입니다.

대신 Count () (IEnumerable도 ICollection 인 경우 O (1)이며 대부분의 내장 IEnumerable에 해당되는 경우)를 사용하고 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을 더 많이 제공하지 않습니까!
한니 세 티아 완

1
마지막 항목은 블록 전에 한 번만 찾을 수 있습니다 ( 메모 홍보 ) foreach. 이와 같이 : var lastItem = objList.LastOrDeafault();. 그런 다음 foreach루프 내부에서 다음과 같이 확인할 수 있습니다 f (item.Equals(lastItem)) { ... }. 원래 답변 objList.LastOrDefault()에서 각 "foreach"반복에서 컬렉션을 반복합니다 ( 폴로 미엄 복잡성이 관련됨 ).
AlexMelw

나쁜 대답입니다. n 대신 n ^ 2 복잡성.
Shimmy Weitzhandler

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

Daniel Wolf의 답변 을 더욱 향상 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
@Servy 나는 그것을 의미한다. 원래 답변의 단일 반복 외에도 람다를 피하고 있습니다.
Fabricio Godoy

7

반복자 구현은이를 제공하지 않습니다. 컬렉션은 IListO (1)의 색인을 통해 액세스 할 수있는 것일 수 있습니다 . 이 경우 일반적인 for루프를 사용할 수 있습니다 .

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

개수를 알고 있지만 인덱스를 통해 액세스 할 수없는 경우 (결과는 ICollection) 신체 i의 를 증가 foreach시키고 길이와 비교하여 스스로를 계산할 수 있습니다 .

이 모든 것이 완벽하게 우아하지는 않습니다. Chris의 솔루션은 내가 지금까지 본 것 중 가장 좋을 것입니다.


foreach idea와 Chris의 솔루션 내에서 카운터 성능을 비교할 때 단일 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
대답이 마지막 항목을 찾는 데 완벽하다는 사실에도 불구하고 OP의 조건 " ..., 루프의 마지막 반복 "을 결정 하지 않습니다 . 따라서 마지막 반복이 실제로 마지막 반복인지 확인할 수 없으므로 다르게 처리하거나 무시할 수 없습니다. 누군가가 당신을 공감 한 이유입니다. @ arviman 당신은 그것에 대해 너무 궁금했다.
AlexMelw

1
당신이 맞아요, @ Andrey-WD를 완전히 놓쳤습니다. 해결해야 할 해결책은 루프 이전에 "last"를 한 번 호출하는 것입니다 (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++;
}


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

Jon Skeet의 탁월한 코드를 약간 조정하면 이전 및 다음 항목에 대한 액세스를 허용하여 더 똑똑하게 만들 수도 있습니다. 물론 이것은 구현에서 한 항목을 미리 읽어야 함을 의미합니다. 성능상의 이유로 이전 및 다음 항목은 현재 반복 항목에 대해서만 유지됩니다. 다음과 같이 진행됩니다.

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

-1for조건은 마지막 항목을 건너 뛰는을 담당한다.


for 루프의 -1은 마지막 항목을 건너 뛰는 것을 처리하지 않습니다. -1을 포함하지 않으면 IndexOutOfRangeException이 발생합니다.
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).
    });

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
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.