我有一个foreach循环,需要执行一些逻辑时,最后一项是从列表中选择,例如:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
我可以知道哪个循环是最后没有使用循环和计数器吗?
我有一个foreach循环,需要执行一些逻辑时,最后一项是从列表中选择,例如:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
我可以知道哪个循环是最后没有使用循环和计数器吗?
当前回答
接受的答案将不适用于集合中的副本。如果设置在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++;
}
其他回答
进一步改进Daniel Wolf的答案,你可以堆叠在另一个IEnumerable上,以避免多次迭代和lambda,例如:
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;
}
}
}
在某些类型上使用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()函数将遍历所有集合元素。
Test
如果你的集合提供了随机访问(例如实现了IList<T>),你也可以像下面这样检查你的项目。
if(collection is IList<T> list)
return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps
只需存储之前的值,并在循环中使用它。然后在最后,“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);
}
还有更简单的方法吗?
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转换为对最后一个元素做出反应:
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();
}