我有一个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循环和计数器的情况下知道哪个循环是最后一个吗?
我有一个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循环和计数器的情况下知道哪个循环是最后一个吗?
对于集合中的重复项,接受的答案无法使用。如果您坚持使用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++;
}
只需存储前一个值并在循环内部处理它。然后在结束时,“previous”值将是最后一个项目,让您以不同方式处理它。无需计数或特殊库。
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);
}
foreach (Item result in Model.Results)
{
if (Model.Results.IndexOf(result) == Model.Results.Count - 1) {
// this is the last item
}
}
根据@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://dev59.com/YVwY5IYBdhLWcg3weXvV#32580613
if (selector != null)
{
yield return selector.Invoke(current);
}
}
}
}
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
}
}
}
foreach
转换为响应最后一个元素的 React: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 (int i = 0; i < Model.Results.Count - 1; i++) {
var item = Model.Results[i];
}
for
条件中的-1
可以跳过最后一个项目。
<
操作,而不是一个<=
操作。 - Taylor C. Whitepublic 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).
});
你可以创建一个专门用于此的扩展方法:
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
}
}
"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 */
);
ForEach
?Dictionary<K, V>
类中没有这样的方法。 - Theodor Zoulias