我有一个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
}
我可以知道哪个循环是最后没有使用循环和计数器吗?
当前回答
迭代器实现没有提供这一点。您的集合可能是一个IList,可以通过O(1)中的索引访问。在这种情况下,你可以使用一个普通的for循环:
for(int i = 0; i < Model.Results.Count; i++)
{
if(i == Model.Results.Count - 1) doMagic();
}
如果您知道计数,但不能通过索引访问(因此,result是一个ICollection),您可以通过在foreach的主体中增加i并将其与长度进行比较来进行计数。
所有这些都不是完美的优雅。克里斯的解决方案可能是我迄今为止见过的最好的。
其他回答
最好的方法可能是在循环之后执行该步骤:
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
要对除最后一个元素之外的每个元素做一些额外的事情,可以使用基于函数的方法。
delegate void DInner ();
....
Dinner inner=delegate
{
inner=delegate
{
// do something additional
}
}
foreach (DataGridViewRow dgr in product_list.Rows)
{
inner()
//do something
}
}
这种方法有明显的缺点:对于更复杂的情况,代码更不清晰。调用委托可能不是很有效。排除故障可能不太容易。好的一面——编码很有趣!
话虽如此,如果你知道你的集合的计数不是特别慢,我建议在一些不重要的情况下使用plain for循环。
你可以创建一个专门用于此的扩展方法:
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()将遍历整个集合! 这意味着如果执行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
你可以这样做:
foreach (DataGridViewRow dgr in product_list.Rows)
{
if (dgr.Index == dgr.DataGridView.RowCount - 1)
{
//do something
}
}