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

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


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.