我有一个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
}
我可以知道哪个循环是最后没有使用循环和计数器吗?
当前回答
只需存储之前的值,并在循环中使用它。然后在最后,“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);
}
其他回答
进一步改进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
你可以创建一个专门用于此的扩展方法:
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 */
);
如果你只需要对最后一个元素做一些事情(而不是对最后一个元素做一些不同的事情),那么在这里使用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
}
}