在递归函数中使用.Find

时间:2016-06-13 19:27:57

标签: function excel-vba vba excel

我试图在递归函数中使用.Find函数在工作表中找到行号。 我设置了一个名为Found = .Find....的对象,它的效果很好......一点点。我在深度递归1级时设置它,然后在我2级深度时再次设置它。然后,我的代码找到路径的结尾并开始备份,直到它回到1级深,但不是我的Found对象已被重新声明并保持其值从第二级。我的其他变量(ThisRow等...)保持它们所处的级别的值,这就是我想要对象Found所做的事情。有没有办法可以在本地声明Found,以便它的值不会扩展到下一个函数,并且不能在更深层次上覆盖?您可以在下面找到我的代码以供参考。

这是我目前的代码 - 不相关的部分:

Public Function FindChildren()

ThisRow = AnswerRow 'Also declared before function call

    BeenHereCell = Cells(ThisRow, "O").Address
    If Range(BeenHereCell).Value = "Yes" Then
        Exit Function 'That means we've already been there
    End If
    Range(BeenHereCell).Value = "Yes"

    With Worksheets("MasterScore").Range("j1:j50000")
        Set Found = .Find(NextQuestionID, LookIn:=xlValues)
        If Not Found Is Nothing Then
            firstAddress = Found.Address
            NextCell = Found.Address
            Do

                AnswerRow = Range(NextCell).Row
                FindChildren 'This is where it's recursive.

                Set Found = .FindNext(Found)
                NextCell = Found.Address

           Loop While Not Found Is Nothing And Found.Address <> firstAddress
        End If
    End With
End Function

现在我通过激活单元来解决它,但它使我的代码慢了很多。目前我正在使用这个:

Set Found = Worksheets("MasterScore").Range("j1:j50000").Find(NextQuestionID, LookIn:=xlValues)
If Not Found Is Nothing Then
    Count = 1
    Do
        Columns("J:J").Select
        FirstFoundRow = Selection.Find(What:=NextQuestionID, After:=ActiveCell, LookIn:= _
        xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
        xlNext, MatchCase:=False, SearchFormat:=False).Row
        For i = 1 To Count
            Selection.FindNext(After:=ActiveCell).Activate
        Next i
        AnswerRow = ActiveCell.Row
        If AnswerRow = FirstFoundRow And Count <> 1 Then Exit Do

        FindChildren
        Count = Count + 1
    Loop
End If

这样,我不必再次设置对象的值,但我必须遍历it.FindNext很多次,并且每次运行该行时它也会激活该行。我真的只想要类似的东西。

AnswerRow = .Find(nth instance of NextQuestionID).Row 

(我有大约5万行,计数经常大约20,所以它真的需要一段时间)。

我很感激任何想法!目前我的代码正在运行,但是需要很长一段时间才能完成,我需要在某个时候再次运行它!

1 个答案:

答案 0 :(得分:0)

我最终找到了一种方法来加快它的速度。我认为这可以帮助别人,所以我将分享我发现的东西。 这不是最好的解决方案(我本来希望只在本地声明对象,这样我的其他函数就不会改变它的值),但至少在这种情况下,我不会循环20次左右找到Do循环的每次迭代。

Set Found = Worksheets("MasterScore").Range("j1:j50000").Find(NextQuestionID, LookIn:=xlValues)
If Not Found Is Nothing Then
    NextAnswerRange = "j" & 1 & ":" & "j50000" 'The first search will be from the beginning

    Do
        Set Found = Worksheets("MasterScore").Range(NextAnswerRange).Find(NextQuestionID, LookIn:=xlValues)
        NextCell = Found.Address
        AnswerRow = Range(NextCell).Row

        NextAnswerRange = "j" & AnswerRow & ":" & "j50000"
        If LastAnswerRange = NextAnswerRange Then Exit Function 'This would mean we've reached the end.
        LastAnswerRange = NextAnswerRange

        FindChildren
    Loop
End If

结束功能

所以我们知道我们已经覆盖了以前范围的基础,因为它总能找到下一个范围。我们每次只更改搜索范围,它会找到下一个值。

这个解决方案的一个奇怪的事情是,如果你正在寻找范围70中的值 - &gt; 50,000你得到你在第70行寻找的答案,它实际上会找到下一行(它跳过第一行)。但是,如果没有任何超过70的行有答案,它实际上会从第70行获取值。这意味着我无法做到

NextAnswerRange = "j" & AnswerRow + 1 & ":" & "j50000"

因为它会错过一些值。如果没有+ 1意味着在文档的最后我会一遍又一遍地搜索相同的最后一个值(它永远不会回到Found Is Nothing)所以我必须检查以查看LastAnswerRange = NextAnswerRange。

我希望这有助于某人。我认为这不是最优雅的解决方案,但它比我的速度快得多。