Excel UDF 过滤器范围
Posted
技术标签:
【中文标题】Excel UDF 过滤器范围【英文标题】:Excel UDF Filter Range 【发布时间】:2012-09-12 20:06:39 【问题描述】:我有一个函数,它以一系列值作为输入(只是一列)以及一些阈值。我想返回一个经过过滤的范围,以包含原始范围中大于阈值的所有值。我有以下代码:
Public Function FilterGreaterThan(Rng As Range, Limit As Double) As Range
Dim Cell As Range
Dim ResultRange As Range
For Each Cell In Rng
If Abs(Cell.Value) >= Limit Then
If ResultRange Is Nothing Then
Set ResultRange = Cell
Else
Set ResultRange = Union(ResultRange, Cell)
End If
End If
Next
Set FilterGreaterThan = ResultRange
End Function
问题在于,一旦某个数字低于阈值,则该数字之后高于阈值的其他数字不会被添加到范围中。
例如:
Threshold - 2
Numbers -
3
4
1
5
它将循环添加 3 和 4,但不会添加 5。我最终得到一个#value 错误。但是我没有收到任何错误,如果我只输入范围 - 3、4 或范围 - 3、4、1,它就可以正常工作。
【问题讨论】:
嗨,如果你把它放在像 =SUM(FilterGreaterThan(A1:A7,2)) 这样的另一个函数中,你的函数就可以正常工作。我认为您遇到的问题是您将 =FilterGreaterThan(A1:A7,2) 放在一个单元格中,当它返回一个多区域范围时,您会得到一个 #VALUE!错误。尽管如此,我还是不明白从 =FilterGreaterThan(A1:A7,2) 返回的结果,因为您只是从该范围内返回一个(似乎是)随机数。 如果在End Function前加上Debug.Print FilterGreaterThan.Address
,就可以看到函数的范围地址。看起来 UDF 可能不喜欢不连续的范围。
【参考方案1】:
看起来 UDF 不喜欢将非连续范围写回数组。
一种解决方法是重写 UDF,如下所示。它假定输出数组仅在列中,但确实允许多列输入。
Option Explicit
Public Function FilterGreaterThan(Rng As Range, Limit As Double) As Variant
Dim Cell As Range
Dim WriteArray() As Variant
Dim i As Long
Dim cellVal As Variant
Dim CountLimit As Long
CountLimit = WorksheetFunction.CountIf(Rng, ">=" & Limit)
ReDim WriteArray(1 To CountLimit, 1 To 1) 'change if more than 1 column
For Each Cell In Rng
cellVal = Cell.Value
If Abs(cellVal) >= Limit Then
i = i + 1 'change if more than 1 column
WriteArray(i, 1) = cellVal 'change if more than 1 column
End If
Next
FilterGreaterThan = WriteArray
End Function
【讨论】:
+1 虽然如果CountLimit
为 0,那么如果作为 UDF 调用,它只会返回 #VALUE!
(而不是 #N/A
)。如果从 VBA 调用,那么如果 CountLimit
为 0,您将收到“下标超出范围”错误
你的权利,没有错误处理,假设 CountLimit>0。
我只是看了一下代码。似乎 CountLimit = WorksheetFunction.CountIf(Rng, ">=" & Limit) 没有考虑绝对值考虑。虽然不知道在哪里添加
我试图偷偷摸摸地获取数组的值,但忘记了 ABS! :)
那个 ABS 是个滑溜溜的小傻瓜 :)【参考方案2】:
ooo 先到了那里,但我现在已经把它打出来了,所以我不妨把它贴出来。此版本将作为正确大小的列向量返回。
如果没有匹配项,则在 1×1 数组中返回 #N/A(这与数组函数在没有足够值填充数组时的正常行为一致)
edit2:感谢来自 ooo 的 cmets 的更新功能
Public Function FilterGreaterThan(Rng As Range, Limit As Double) As Variant()
Dim inputCell As Range ' each cell we read from
Dim resultCount As Integer ' number of matching cells found
Dim resultValue() As Variant ' array of cell values
resultCount = 0
ReDim resultValue(1 To 1, 1 To Rng.Cells.Count)
For Each inputCell In Rng
If Abs(inputCell.Value) >= Limit Then
resultCount = resultCount + 1
resultValue(1, resultCount) = inputCell.Value
End If
Next inputCell
' Output array must be two-dimensional and we can only
' ReDim Preserve the last dimension
If (resultCount > 0) Then
ReDim Preserve resultValue(1 To 1, 1 To resultCount)
Else
resultValue(1, 1) = CVErr(xlErrNA)
ReDim Preserve resultValue(1 To 1, 1 To 1)
End If
' Transpose the results to produce a column rather than a row
resultValue = Application.WorksheetFunction.Transpose(resultValue)
FilterGreaterThan = resultValue
End Function
编辑:使用下面评论中的测试值对我来说可以正常工作:
我确定您知道这一点,但在输入数组公式时不要包含 或
字符 - Excel 会在您按下 Ctrl-Shift-Enter 后添加它们
【讨论】:
谢谢!不幸的是,您的代码继续出现#value 错误。有什么想法吗?我正在使用的示例:要过滤的 Rng 值:-0.003742158,0.004134996,-0.002937923 限制:0.0008 你的答案是正确的。我要做的唯一更改是在开始时将数组调暗为全尺寸,在转置之前仅在结尾处将ReDim Preserve resultValue(1 To 1, 1 To resultCount)
调暗一次 - 你已经获得了rng.cells.count
的最大数组大小。此外,如果只有 1 个单元格,我们两个都将 resultValue 视为一个值而不是数组 :)
@ooo 谢谢 - 我已经更新了我的答案以纳入这些建议以上是关于Excel UDF 过滤器范围的主要内容,如果未能解决你的问题,请参考以下文章