【问题标题】:Is it possible to do a For...Each Loop Backwards?是否可以向后执行 For...Each 循环?
【发布时间】:2009-06-04 17:56:52
【问题描述】:

我不相信传统方法可以做到这一点,但是像这样冗长的代码:

For Each s As String In myStringList Step -1
    //' Do stuff here
Next

我可能必须在传统的 For..Each 循环之前反转 myString 对象,对吗?

【问题讨论】:

    标签: vb.net for-loop


    【解决方案1】:

    我认为Mike's answer below 中引用的文档非常具有误导性。 For Each 的顺序由它所调用的集合定义(即它的 IEnumerable/IEnumerable<T> 的实现),但这与说它不应该在顺序时使用它相同很重要。许多集合(例如数组、List<T> 等)总是按“自然”顺序排列。

    部分文档确实提到了这一点:

    遍历顺序。当你执行一个 For Each...Next 循环,遍历 收集是在控制之下 返回的枚举器对象 GetEnumerator 方法。的顺序 遍历不是由 Visual 决定的 基本,而是由 MoveNext 枚举器对象的方法。这 意味着您可能无法 预测哪个元素 收藏是第一个被退回的 在元素中,或者下一个是 在给定元素之后返回。

    这与说它不能被依赖完全不一样——它可以被依赖如果你知道你正在迭代的集合会以期望的顺序产生结果 .它不会随机选择元素。 IEnumerable/IEnumerable<T> 的行为在该页面上已明确定义。

    可预测排序的最重要例外是字典和集合,它们自然是无序的。

    要反转 IEnumerable<T>,请使用 Enumerable.Reverse - 但如果您需要反向迭代按位置索引的集合(例如数组或 List<T>),那么使用For 循环从末尾开始并向后工作。

    【讨论】:

    • 感谢乔恩,很高兴得到您的意见和见解:D
    • 为什么这个答案不被接受?它的例子更深入
    • @DotNet 程序员:这是一篇旧帖子,我意识到我当时没有接受真正的答案:)现在已经给予了适当的信用(不是说乔恩无论如何都需要更多积分:P)
    【解决方案2】:

    您必须执行以下操作:

    For i as integer = myStringList.Count-1 to 0 step -1
        dim s as string = myStringList.Item(i)
        ' Do your stuff with s
    Next i
    

    但据我所知,您不能向后执行“For...Each”,尽管在某些情况下会很好。

    【讨论】:

    • 没错。我只是确保我没有错过 VB 的一些很酷的“隐藏”功能,也就是没有充分记录的功能。
    • 这太完美了!
    • 如果你像我一样偶然发现这里,那么可能会感兴趣:stackoverflow.com/questions/24358183/…
    【解决方案3】:

    遗憾的是,MSDN docs on For Each 声明 For Each 构造对于迭代顺序不重要的情况(无序集等)显式存在。所以不幸的是没有反转 For Each 的概念,因为无论如何都没有定义顺序。

    祝你好运!

    【讨论】:

    • 我期待这一点,但我不是 100% 确定,所以感谢您提供明确的不带参考作为奖励:)
    • 这是正确的——我总是假设“For Each”循环按顺序进行,虽然它们通常这样做,但不能依赖它。如果你想要一个特定的顺序,数组中索引上的“For...Next”是你唯一的选择。
    • 如果你知道你正在使用的集合以正确的顺序迭代,它可以被依赖。例如,数组将总是以自然顺序迭代。详情请参阅我的回答。
    • (因为“无论如何都没有定义订单”的说法被否决 - 它是由集合本身定义的。)
    • Mike 链接的 MSDN 页面证实了 Jon Skeet 所说的 [否则它不敢做] - “遍历的顺序不是由 Visual Basic 确定的,而是由枚举器对象。”。所以顺序 定义的,但是由被迭代的集合而不是由 For Each 语句本身来定义。
    【解决方案4】:

    调用System.Linq.Enumerable.Reverse 方法以与可枚举源相反的顺序获取IEnuemrable(Of TSource)

    【讨论】:

    • 是的,这就是我最终要做的。谢谢!
    • 我不知道这行得通,但奇怪的是,MSDN 示例反转了数组,然后使用“For Each”循环继续遍历它,这在需要特定顺序时明显不可靠.哎呀...
    • 所有 foreach'able 类型都实现 GetEnumerator()。一些枚举器具有可靠的排序,而有些则没有。由于我们正在讨论反转顺序,因此我们正在处理的 Enumerator 很可能具有可靠的反转顺序。当然,并不是所有的 Enumerators 都符合这个标准。可以肯定的是,数组的枚举器是可靠有序且可逆的。
    • 答案不应仅限链接。
    • @cybermonkey 这不仅仅是链接。这是链接+句子。有时更多的词并不能改善答案。
    【解决方案5】:

    在Framework 4中测试,代码

    For Each s As String In myStringList.Reverse
        //' Do stuff here
    Next
    

    它不起作用,正确的方法是:

    myStringList.Reverse() ' it is a method not a function
    For Each s As String In myStringList
    //' Do stuff here
    Next
    

    看:MSDN: Reserve

    【讨论】:

      【解决方案6】:
      For Each s As String In myStringList.Reverse
          //' Do stuff here
      Next
      

      【讨论】:

        【解决方案7】:

        无法做到这一点的原因是,作为一项基本设计功能,For Each 可以迭代一个没有最后一个元素的可枚举对象,或者使用一个未知的最后一个元素。

        【讨论】:

          【解决方案8】:

          这行得通:

          Dim myArray() As String = {"1", "2", "3", "4", "5"}
          
          For Each n As String In myArray.Reverse
              Debug.Print(n)
          Next
          

          输出:5 4 3 2 1

          '

          这也有效:

          Dim myArray() As String = {"1", "2", "3", "4", "5"}
          
          For i As Integer = myArray.Length - 1 To 0 Step -1
              Debug.Print(myArray(i))
          Next
          

          输出:5 4 3 2 1

          【讨论】:

            【解决方案9】:

            你需要做的是用你之前的 for each 创建一个数组,然后使用 array.reverse 并在数组上运行 for each。完成

            干杯

            【讨论】:

            • 嗨 xxxmandoxxx。在添加答案之前,您应该检查是否已经存在相同的答案。您的回答不会增加帖子的价值。
            【解决方案10】:

            根据循环内部发生的情况,您可以执行 .InsertAt(object,0) 而不是 .Add 并产生与反向枚举相同的结果。

            【讨论】:

              【解决方案11】:

              你可以给你想要反转的类添加一个扩展函数

              <Serializable()> Public Class SomeCollection
                  Inherits CollectionBase
                  Public Sub New()
                  End Sub
              
                  Public Sub Add(ByVal Value As Something)
                      Me.List.Add(Value)
                  End Sub
              
                  Public Sub Remove(ByVal Value As Something)
                      Me.List.Remove(Value)
                  End Sub
              
                  Public Function Contains(ByVal Value As Something) As Boolean
                      Return Me.List.Contains(Value)
                  End Function
              
                  Public Function Item(ByVal Index As Integer) As Something
                      Return DirectCast(Me.List.Item(Index), Something)
                  End Function
              
                  Public Function Reverse() As SomeCollection
                      Dim revList As SomeCollection = New SomeCollection()
                      For index As Integer = (Me.List.Count - 1) To 0 Step -1
                           revList.List.Add(Me.List.Item(index))
                      Next
                      Return revList
                  End Function
              End Class
              

              那你就这样称呼它

              For Each s As Something In SomeCollection.Reverse
              
              Next
              

              【讨论】:

                【解决方案12】:

                首先你应该为每个语句创建一个列表(字符串),然后为 .. step -1 ..next 语句创建另一个正常的。看一个例子:

                Dim ff As New List(Of Integer)
                For Each rRow As DataRow In DeletedRows
                Dim item As Integer
                item = rRow.Table.Rows.IndexOf(rRow)
                ff.Add(item)
                Next
                For i As Integer = ff.Count - 1 To 0 Step -1
                dim item as integer=ff(i)
                next i
                

                希望对你有帮助

                【讨论】:

                  【解决方案13】:

                  接受的答案解释了原因,但要添加另一个示例,对于带有键的集合(SortedList、SortedDictionary、Dictionary 等),您可以这样做

                  For Each Id as Tkey in MyCollection.Keys.Reverse
                     // The item in question is now available as MyCollection(Id)
                  Next
                  

                  【讨论】:

                    【解决方案14】:

                    ' 创建一个列表并逐步完成 For 循环收集

                    dim revList as New List (of ToolStripItem)  
                    For each objItem as ToolStripItem in Menu.DropDownItems
                        revList.Add(objItem)
                    next
                    revList.reverse ' reverse the order of that list
                    

                    ' 遍历逆序列表

                    for each objItem as ToolStripItem in revList   
                        ' do whatever (like removing your menu from an ArrayMenu)
                    next
                    

                    ' 用你需要的任何东西替换 ToolStripItem 和 Menu.DropDownItems

                    【讨论】:

                      猜你喜欢
                      • 2018-11-14
                      • 1970-01-01
                      • 2017-07-06
                      • 2015-11-12
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-08-22
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多