각 루프에 대해 루프의 마지막 반복을 결정합니다.
나는 있습니다foreach
루프 및 마지막 항목이 선택될 때 몇 가지 논리를 실행해야 합니다.List
예:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
루프와 카운터에 사용하지 않고 어떤 루프가 마지막인지 알 수 있습니까?
마지막 요소와 다른 요소를 사용하는 것이 아니라 마지막 요소를 사용하는 것이 필요한 경우 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
}
}
루프용으로 만들어진 좋은 구식 제품은 어떻습니까?
for (int i = 0; i < Model.Results.Count; i++) {
if (i == Model.Results.Count - 1) {
// this is the last item
}
}
또는 각각의 Linq 및 for를 사용합니다.
foreach (Item result in Model.Results)
{
if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
// this is the last item
}
}
사용.Last()
특정 유형에서 전체 컬렉션을 순환합니다!
그 말은 만약 당신이 만든다면.foreach
와 콜Last()
당신은 두 번 루프했습니다!당신이 많은 수집품에서 피하고 싶어할 것이라고 확신합니다.
그렇다면 해결책은 다음과 같습니다.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
Chris가 보여주듯이, Linkq는 작동할 것입니다. Last()를 사용하여 열거형의 마지막 참조를 가져오고, 해당 참조로 작업하지 않는 한 일반 코드를 수행하지만, 해당 참조로 작업하는 경우 추가 작업을 수행합니다.단점은 항상 O(N)-복잡하다는 것입니다.
대신 Count()(IE 숫자가 I 모음이기도 한 경우 O(1)이며, 이는 대부분의 일반적인 내장 IE 숫자에 해당합니다.)를 사용하여 각 항목을 카운터와 하이브리드할 수 있습니다.
var i=0;
var count = Model.Results.Count();
foreach (Item result in Model.Results)
{
if (++i == count) //this is the last item
}
var last = objList.LastOrDefault();
foreach (var item in objList)
{
if (item.Equals(last))
{
}
}
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; }
}
}
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;
}
}
}
반복기 구현에서는 이를 제공하지 않습니다.은 컬션이같수있다습니일 수.IList
O(1)의 인덱스를 통해 액세스할 수 있습니다.그런 경우에는 일반적인 방법을 사용할 수 있습니다.for
loop:
for(int i = 0; i < Model.Results.Count; i++)
{
if(i == Model.Results.Count - 1) doMagic();
}
카운트를 알고 있지만 인덱스를 통해 액세스할 수 없는 경우(따라서 결과는ICollection
), , , 를을 셀 수 i
에 시대에foreach
몸의 길이와 비교하는 것.
이 모든 것이 완벽하게 우아하지는 않습니다.크리스의 해결책은 제가 지금까지 본 것 중에 가장 좋을 것입니다.
가장 좋은 방법은 루프 후에 해당 단계를 실행하는 것입니다. 예를 들어,
foreach(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
조금 더 간단한 접근법은 어떨까요?
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);
컬렉션의 중복 항목에 대해 승인된 답변이 작동하지 않습니다.설정된 경우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++;
}
각각의 Linq 및 for를 사용합니다.
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
@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
을 추로가, 당은이만수있들다습니것을신▁a▁this로 만들 수 있습니다.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);
}
}
}
}
이전 값을 저장하고 루프 내에서 작업하기만 하면 됩니다.그러면 마지막에 '이전' 값이 마지막 항목이 되어 다르게 처리할 수 있습니다.계수나 특수 라이브러리가 필요하지 않습니다.
bool empty = true;
Item previousItem;
foreach (Item result in Model.Results)
{
// Alternatively, check if previousItem == null
// if your Enumerable can't contain nulls
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);
}
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<T> 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
}
}
}
제가 게시된 것을 보지 못한 또 다른 방법은 큐를 사용하는 것입니다.이는 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).
});
변환 방법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();
}
당신은 그냥 for 루프를 사용할 수 있으며 추가할 필요가 없습니다.if
에의 에.for
표시된 내용:
for (int i = 0; i < Model.Results.Count - 1; i++) {
var item = Model.Results[i];
}
그-1
에 시대에for
조건은 마지막 항목을 건너뛰는 것을 처리합니다.
".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 */
);
이를 위해 특별히 전용 확장 방법을 만들 수 있습니다.
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
}
}
마지막 요소를 제외한 각 요소에 추가적인 작업을 수행하려면 함수 기반 접근 방식을 사용할 수 있습니다.
delegate void DInner ();
....
Dinner inner=delegate
{
inner=delegate
{
// do something additional
}
}
foreach (DataGridViewRow dgr in product_list.Rows)
{
inner()
//do something
}
}
이 접근 방식에는 명백한 단점이 있습니다. 즉, 복잡한 경우에는 코드 명확성이 떨어집니다.딜러에게 전화를 거는 것은 그다지 효과적이지 않을 수 있습니다.문제 해결이 쉽지 않을 수 있습니다.긍정적인 면 - 코딩은 재미있습니다!
그렇기는 하지만, 수집의 수가 심각하게 느리지 않다는 것을 안다면 사소한 경우에 루프에 플레인을 사용하는 것을 제안합니다.
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++;
}
다음과 같이 할 수 있습니다.
foreach (DataGridViewRow dgr in product_list.Rows)
{
if (dgr.Index == dgr.DataGridView.RowCount - 1)
{
//do something
}
}
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++;
}
언급URL : https://stackoverflow.com/questions/7476174/foreach-loop-determine-which-is-the-last-iteration-of-the-loop
'programing' 카테고리의 다른 글
app.config에 의존하지 않고 SOAP 웹 서비스를 사용합니다. (0) | 2023.05.25 |
---|---|
공백을 포함한 줄 길이별로 텍스트 파일 정렬 (0) | 2023.05.25 |
할당 표현식이란 무엇입니까("왈러스" 또는 ":=" 연산자 사용)?이 구문이 추가된 이유는 무엇입니까? (0) | 2023.05.25 |
Winforms에서 컨트롤에 대한 속성 바인딩 (0) | 2023.05.25 |
쿼리를 사용하여 기존 테이블에 대한 SQL 생성 스크립트 생성 (0) | 2023.05.25 |