【问题标题】:Range and ActiveCell.Offset Run-time error '1004'Range 和 ActiveCell.Offset 运行时错误 '1004'
【发布时间】:2014-07-12 17:33:26
【问题描述】:

我正在尝试确定工作表中所有非空白行的 5 个单元格范围 (C:G) 的最小值和最大值,并将各自的结果放在 L 和 M 列中。

我收到运行时错误“1004”应用程序定义或对象定义错误。

Sub test()
    ActiveSheet.Range("A1").Select
    ActiveCell.Offset(1, 0).Select
    Do While ActiveCell.Value <> Empty
        ActiveCell.Offset(0, 11) = WorksheetFunction.Min(Range(ActiveCell.Offset(0, 2), ActiveCell.Offset(0, 6)))
        ActiveCell.Offset(0, 12) = WorksheetFunction.Max(Range(ActiveCell.Offset(0, 2), ActiveCell.Offset(0, 6)))
        ActiveCell.Offset(1, 0).Select
    Loop
    ActiveSheet.Range("A1").Select
End Sub

我很确定我的问题出在范围规范中,但不确定是什么。

第一个和最后一个选择只是我使用的约定。

第二个选择是跳过标题行。

第三个选择是增加行数。

如果有更简单的方法,请告诉我。

【问题讨论】:

标签: excel vba


【解决方案1】:

我无法重现您提到的错误,您的代码似乎按原样运行。

也就是说有很多方法可以改进这段代码

  1. 避免使用Select(如 cmets 中所述)
  2. Application 对象提供了MinMax 功能,这些不需要使用WorksheetFunctions
  3. range 引用的更好方法是 OffsetResize 的组合

您的代码,重构为使用这些技术

Sub Demo()
    Dim ws As Worksheet
    Dim rng As Range
    Dim rw As Range

    ' Get a reference to the source data range
    Set ws = ActiveSheet
    With ws
        Set rng = .Cells(2, 1)
        ' Just in case there is only one data row
        If Not IsEmpty(rng.Offset(1, 0)) Then
            Set rng = .Range(rng, rng.End(xlDown))
        End If
    End With

    ' Loop the range
    For Each rw In rng.Rows
        rw.Offset(0, 11) = Application.Min(rw.Offset(0, 1).Resize(, 5))
        rw.Offset(0, 12) = Application.Max(rw.Offset(0, 1).Resize(, 5))
    Next
End Sub

也就是说,您可以更进一步并使用Variant Array 方法。这比循环范围快得多(影响会因数据行数而异)

Sub Demo2()
    Dim ws As Worksheet
    Dim rng As Range
    Dim dat As Variant
    Dim res As Variant
    Dim i As Long

    ' Get a reference to the source data range
    Set ws = ActiveSheet
    With ws
        Set rng = .Cells(2, 1)
        ' Just in case there is only one data row
        If Not IsEmpty(rng.Offset(1, 0)) Then
            Set rng = .Range(rng, rng.End(xlDown))
        End If
    End With

    ' Set up source and result arrays
    dat = rng.Offset(, 2).Resize(, 5).Value
    ReDim res(1 To UBound(dat, 1), 1 To 2)

    With Application
        ' Loop the array
        For i = 1 To UBound(dat, 1)
            res(i, 1) = .Min(.Index(dat, i))
            res(i, 2) = .Max(.Index(dat, i))
        Next
    End With

    ' Return results to sheet
    rng.Offset(0, 11).Resize(, 2) = res
End Sub

另一种技术是通过(临时)一次性将公式放入工作表中来完全避免循环。这将快得多(对于多个数据行)

Sub Demo3()
    Dim ws As Worksheet
    Dim rng As Range
    Dim rw As Range

    ' Get a reference to the source data range
    Set ws = ActiveSheet
    With ws
        Set rng = .Cells(2, 1)
        If Not IsEmpty(rng.Offset(1, 0)) Then
            Set rng = .Range(rng, rng.End(xlDown))
        End If
    End With

    ' Place formulas into sheet
    rng.Offset(0, 11).FormulaR1C1 = "=Min(RC[-9]:RC[-5])"
    rng.Offset(0, 12).FormulaR1C1 = "=Max(RC[-9]:RC[-5])"

    ' replace formulas with values (optional)
    rng.Value = rng.Value
End Sub

【讨论】:

  • 克里斯,你的建议很有效 - 比你的帮助。
  • 克里斯,您的建议效果很好 - 感谢您的帮助。你对细节的关注(空行检查)让我觉得你做 vba 已经有一段时间了。你能为初学者推荐一本好书吗?
【解决方案2】:

这个怎么样?

Sub MinAndMax()
    Dim rng As Range
    Set rng = Range("A2:A" & Range("A2").End(xlDown).Row)

    Range("L1") = WorksheetFunction.Min(rng)
    Range("M1") = WorksheetFunction.Max(rng)
End Sub
  • 预先定义范围
  • minmax 直接写入单元格

【讨论】:

  • 亚历克斯,感谢您的回复。我在最初的问题中犯了错误。我应该说“对于每个非空白行”而不是“对于所有非空白行”——我希望为每一行创建最小值/最大值。
猜你喜欢
  • 2017-10-19
  • 2020-08-03
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-25
相关资源
最近更新 更多