你如何找到 For Each (VB.NET) 中的最后一个循环?

Posted

技术标签:

【中文标题】你如何找到 For Each (VB.NET) 中的最后一个循环?【英文标题】:How do you find the last loop in a For Each (VB.NET)? 【发布时间】:2010-09-27 10:43:57 【问题描述】:

如何确定我是否处于 VB.NET 中 For Each 语句的最后循环中?

【问题讨论】:

【参考方案1】:

通常,您可以在其上执行For Each 的集合实现IEnumerator 接口。这个接口只有两个方法MoveNextReset和一个属性Current

基本上,当您在集合上使用For Each 时,它会调用MoveNext 函数并读取返回的值。如果返回值为True,则表示集合中有有效元素,该元素通过Current属性返回。如果集合中没有更多元素,则MoveNext 函数返回False 并退出迭代。

从上面的解释中,很明显For Each 不会跟踪集合中的当前位置,因此您的问题的答案是简短的 .

但是,如果您仍然想知道您是否在集合中的最后一个元素上,您可以尝试以下代码。它检查(使用 LINQ)当前项是否是最后一项。

For Each item in Collection
    If item Is Collection.Last Then
        'do something with your last item'
    End If
Next

了解对集合调用Last() 将枚​​举整个集合,这一点很重要。因此不建议对以下类型的集合调用Last()

流式集合 计算成本高的集合 突变倾向高的集合

对于此类集合,最好获取集合的枚举器(通过GetEnumerator() 函数),以便您自己跟踪项目。下面是一个通过扩展方法实现的示例实现,该方法产生项目的索引,以及当前项目是集合中的第一项还是最后一项。

<Extension()>
Public Iterator Function EnumerateEx(Of T)(collection As IEnumerable(Of T))
    As IEnumerable(Of (value As T, index As Integer, isFirst As Boolean, isLast As Boolean))

    Using e = collection.GetEnumerator()
        Dim index = -1
        Dim toYield As T

        If e.MoveNext() Then
            index += 1
            toYield = e.Current
        End If

        While e.MoveNext()
            Yield (toYield, index, index = 0, False)
            index += 1
            toYield = e.Current
        End While

        Yield (toYield, index, index = 0, True)
    End Using
End Function

这是一个示例用法:

Sub Main()
    Console.WriteLine("Index   Value   IsFirst   IsLast")
    Console.WriteLine("-----   -----   -------   ------")

    Dim fibonacci = 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89

    For Each i In fibonacci.EnumerateEx()
        Console.WriteLine(String.Join("   ", $"i.index,5",
                                             $"i.value,5",
                                             $"i.isFirst,-7",
                                             $"i.isLast,-6"))
    Next

    Console.ReadLine()
End Sub

输出

索引值 IsFirst IsLast ----- ----- -------- ------ 0 0 真 假 1 1 错误 错误 2 1 错误 错误 3 2 错误 错误 4 3 错误 错误 5 5 错误 错误 6 8 错误 错误 7 13 错误 错误 8 21 错误 错误 9 34 错误 错误 10 55 错误 错误 11 89 假真

【讨论】:

很好的解释,通常是一个很好的解决方案。我要指出,这不适用于某些集合,例如 DataTable.Rows,因为 DataRowCollection 没有属性 .Last。另一种选择是另一个答案中提到的计数器。【参考方案2】:

使用 For 循环而不是 ForEach 可能会更容易。但是,类似地,您可以在 ForEach 循环中保留一个计数器,看看它是否等于 yourCollection.Count - 1,那么您就处于最后一次迭代中。

【讨论】:

好吧,如果我需要这样做,我通常会这样做,但我只是想有一些聪明的方法可以在 For Each 或其他东西中确定这一点。【参考方案3】:

使用 foreach,您无法知道这一点,直到为时已晚(即您脱离了循环)。

注意,我假设您使用的东西只有一个 IEnumerable 接口。如果您有列表、数组等,请按照此处使用 .Count 或类似方法的其他答案来找出有多少项目,因此您可以跟踪您在集合中的位置。

但是,如果仅使用 IEnumerable/IEnumerator,则无法确定是否还有更多,如果您使用 foreach。

如果您需要知道这一点,请自己使用 IEnumerable,这就是 foreach 所做的。

以下解决方案适用于 C#,但应该很容易转换为 VB.NET:

List<Int32> nums = new List<Int32>();
nums.Add(1);
nums.Add(2);
nums.Add(3);

IEnumerator<Int32> enumerator = nums.GetEnumerator();
if (enumerator.MoveNext())

    // at least one value available
    while (true)
    
        // make a copy of it
        Int32 current = enumerator.Current;

        // determine if it was the last value
        // if not, enumerator.Current is now the next value
        if (enumerator.MoveNext())
        
            Console.Out.WriteLine("not last: " + current);
        
        else
        
            Console.Out.WriteLine("last: " + current);
            break;
        
    

enumerator.Dispose();

这将打印:

not last: 1
not last: 2
last: 3

诀窍是获取当前值的副本,然后让枚举器尝试移动到下一个值。如果失败,则您制作的副本确实是最后一个值,否则还有更多。

【讨论】:

【参考方案4】:

简短回答:你不能

长答案:For Each 语句的语义中没有任何内容可以让您确定您是在运行第一次、最后一次还是任何特定的迭代。

For Each 内置于 IEnumerable 和 IEnumerable 接口中,其行为取决于您调用的实现。对于您正在迭代的集合以每次都以不同的顺序返回元素,这是有效的,尽管令人困惑。幸运的是,List 没有这样做。

如果您确实需要知道特定迭代是最后一次,您可以(提前)识别最后一个元素,然后在遇到该元素时采取不同的操作。

更简单的方法是检测 第一次 迭代(例如,通过布尔值),然后做一些不同的事情。

一个例子(C#,但 VB 类似):

StringBuilder result = new StringBuilder();
bool firstTime = true;
foreach(string s in names)

    if (!firstTime)
    
        result.Append(", ");
    

    result.Append(s);
    firstTime = false;

【讨论】:

你忘记了 firstTime=false;在第一次循环迭代之后。 糟糕!感谢您的捕获 - 现在已修复。【参考方案5】:

这是一个简单的事情,我不知道它是否在政治上正确,但它有效

for each item in listOfThings
   if(item = listOfThings.last)then 
       'you found the last loop
   end if
next 

【讨论】:

我必须使用 is 关键字来检查。 if item is listOfThings.last then【参考方案6】:

检查元素是否是容器的最后一个元素。

您为什么要这样做? 您可以在循环之后放置指令。 (你在最后一个元素上执行)

【讨论】:

【参考方案7】:

使用 For 循环而不是 ForEach 会更容易,但是您可以执行类似的操作

If item.Equals(itemCollection(itemCollection.Count)) Then
    ...
End If

在您的 ForEach 循环内...假设对象已正确覆盖 Equals 方法。

这可能比仅使用 For 循环或在单独的变量中跟踪当前索引更耗费资源。

我不确定这是否是正确的语法,我已经很久没有使用VB了。

【讨论】:

【参考方案8】:

不能使用标准的“For Each”循环。 “for Each”循环的目的是让您专注于数据而不是基础集合。

【讨论】:

【参考方案9】:

我不断回到这篇文章,所以我决定坐下来思考这个问题,然后我想出了这个:

    For Each obj In myCollection
        Console.WriteLine("current object: 0", obj.ToString)

        If Object.ReferenceEquals(obj, myCollection.Last()) Then
            Console.WriteLine("current object is the last object")
        End If
    Next

如果您愿意,您甚至可以将 If...Then...End If 语句减少为一行。我不确定在每次迭代中调用 .Last() 是否会对性能产生很大影响,但如果这会让您夜不能寐,您可以随时将其分配给循环外的变量。

【讨论】:

创意+1。如果您对此获得更多支持,我会将其切换为答案。 我的代码的一个问题是,如果集合多次包含最后一个对象实例,则当前对象可能通过测试,而不管它是否也是序列中的最后一个对象。您可以自行决定这是错误还是功能。出于这个原因,保留一个计数器(遗憾的是)仍然是迄今为止最好的解决方案。【参考方案10】:

此代码示例可能会有所帮助

For Each item in Collection
  If ReferenceEquals(Collection.Item(Collection.Count - 1), item) Then
    'do something with your last item'
  End If
Next

【讨论】:

【参考方案11】:

如果您绑定到 IEnumerable。你必须在 foreach 循环内吗?如果不是,您可以在 foreach 循环之前声明一个变量。在循环期间设置它。然后,在循环之后使用它(如果它不为空)

【讨论】:

【参考方案12】:

好吧,解决方法很少 假设您正在使用 CheckBoxList

那么这个代码示例可能会有所帮助:

Dim count As Integer = 0
Dim totalListCount As Integer = CheckBoxList.Items.Count()
For Each li In CheckBoxList.Items
         count += 1
           // This is the Last Item
      If count = totalListCount THEN
          // DO Somthing.....
      END IF
NEXT     

【讨论】:

【参考方案13】:
For Each xObj In xColl
    If xObj = xColl(xColl.Count) Then ...
Next

【讨论】:

inbuild 函数可用于检查循环中的最后一个是 Collection.Last

以上是关于你如何找到 For Each (VB.NET) 中的最后一个循环?的主要内容,如果未能解决你的问题,请参考以下文章

日期时间范围 vb.net for 循环

你如何在 EJS 中执行 for 循环/for each?

如何在 VB.Net winforms 应用程序中找到 main() 入口点?

VB.net中如何嵌套EXCEL?

vb.net怎么添加类

如何在自动化服务器列表中安装并注册用 VB.NET 编写的 COM Server for Excel?