2017-01-16 209 views
0

我一直在阅读相关的线程几个小时,但似乎无法找到解决方案。非常感谢您的帮助,谢谢。Excel vba:.find函数返回运行时错误91

我想找到一个范围内的最大值,然后找到它所在的行。 此代码适用于我的第一个600多行数字,然后崩溃,并给我运行时错误91.它似乎总是崩溃不管我做什么,都在同一个地点。

Dim rSearchRange As Range 
Dim dMaxToFind As Double 
Dim rSolutionrange As Range 

Set rSearchRange = Sheets("MySheet").Range(Cells(672, 1), Cells(681, 1)) 

With Application.WorksheetFunction 
     dMaxToFind = .Max(rSearchRange) 
End With 

'This bit here returns "nothing" even though i found the max value in this range 
Set rSolutionrange = rSearchRange _ 
      .Find(What:=dMaxToFind, _ 
      LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, _ 
      SearchDirection:=xlNext, MatchCase:=False) 

看着我的数据,它看起来像它改变了这些行的格式?

Row 670 - 0.000458587 
    Row 671 - 0.000458587 
    Row 672 - 9.80465E-05 
    Row 673 - 9.80465E-05 

编辑:

dMaxToFind返回9.80465352566588E-05

细胞公式返回0.0000980465352566588

它是在细胞范围之间的相同的值(将细胞(672,1),将细胞( 681,1)

好像vba不能理解那两个是一样的吗?

谢谢,

马克

+3

试试'...看着:= xlValues ...'' – user3598756

+1

将.Find'如果没有匹配搜索条件返回'Nothing'。当你稍后*使用'rSolutionRange'对象变量并且假设它被设置为有效引用('Nothing'不是有效的对象引用)时,错误91被*引发*(不是“返回”) - 您需要检查'如果rSolutionRange是Nothing,则在使用它之前。 –

+1

如果'Sheets(“MySheet”)'不是活动工作表,'Sheets(“MySheet”)。Range(Cells(672,1),Cells(681,1))''会爆炸,因为'Cells xxx,yyy)'调用隐式引用'ActiveSheet',所以你也需要限定这些调用;使用'With Worksheets(“MySheet”)'然后'Set rSearchRange = .Range(.Cells(672,1),.Cells(681,1))'在'With'块内(注意点)。 –

回答

0

这里是一个函数,它会直接告诉你的行号。这与您在构建函数中使用以获得最大值然后再次找到它的方法相反!

Function GetMaxRow(ByRef myRange As Range) As Long 

    Dim aCell As Range 

    Dim maxVal As Double 
    Dim maxRow As Long 

    maxVal = Application.WorksheetFunction.Min(myRange) 
    maxRow = 0 

    For Each aCell In myRange 

     If aCell.Value > maxVal Then 

      maxRow = aCell.row 
      maxVal = aCell.Value 

     End If 

    Next aCell 

    GetMaxRow = maxRow 

End Function 

您可能需要一些错误检查的代码添加到该函数的结果,例如,当函数返回0,那就意味着你没有通过它的范围超过1个细胞。

例子:

1 - 3.0 
2 - 5.2 
3 - 7.8 
4 - 2.2 
5 - 4.5 
6 - 3.6 

Dim rw as Long 
rw = GetMaxRow(ActiveSheet.Range("A1:A6")) 
' >> rw = 3 

编辑:

您查询的循环语句使用,因为节省时间的推测。下面是一个时间表,当然这将在不同的计算机上有所不同,但是你可以看到它是一个相当快的例程,除非你的数据集很大......而且这个操作的顺序与预期的一样是线性的,这意味着将范围加倍大约两倍所花费的时间。

2000 rows: 0.0050000s 
4000 rows: 0.0099219s 
8000 rows: 0.0196875s 
16000 rows: 0.0392969s 

测试了该单元格的值是随机双打0和1之间

编辑2:

您见顶那么的循环在一定范围内,而不是...我对速度感兴趣(慢)我写了相同的功能,但使用一个数组。范围被转换为数组,然后循环。这提供了〜10倍的速度提升!有关相同数据的代码和时间,请参见下文。

Function GetMaxRow(ByRef myRange As Range) As Long 

    Dim i As Long 

    Dim maxVal As Variant 
    Dim maxRow As Long 

    maxVal = Application.WorksheetFunction.Min(myRange) 
    maxRow = 0 

    Dim myArray() As Variant 
    myArray = myRange 

    For i = 1 To myRange.Count 

     If myArray(i, 1) > maxVal Then 

      maxRow = i 
      maxVal = myArray(i, 1) 

     End If 

    Next i 

    GetMaxRow = myRange.Cells(maxRow).Row 

End Function 

时序:

2000 rows: 0.0006250s 
4000 rows: 0.0018750s 
8000 rows: 0.0034375s 
16000 rows: 0.0068750s 
+0

这看起来不错 - 有没有任何方式做同样的事情没有循环? – Mark

+0

谢谢,你是因为时机问的吗?看到我的编辑... – Wolfie

+0

@Mark,我添加了更快的版本,请参阅编辑2 – Wolfie