首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WorksheetFunction.Filter中的错误数据类型

WorksheetFunction.Filter中的错误数据类型
EN

Stack Overflow用户
提问于 2020-06-05 02:08:08
回答 7查看 3.5K关注 0票数 6

我正在尝试创建一个函数MonstersInLevel(),它根据第一列的值过滤"LevelMonsters“命名范围的第二列。range的第一列表示游戏级别ID,第二列表示出现在该级别中的怪物ID。我的射程是这样的。

如果我调用MonstersInLevel(2),我希望函数返回一个由"2“、"3”和"4“组成的范围。

代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Range
    MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), Range("LevelMonsters").Columns(1) = level)
End Function

我得到:

公式中使用的值的数据类型是错误的。

我像使用Excel公式一样使用FILTER函数。我认为,对于过滤器的标准,Excel和VBA语法有一些不同。

EN

回答 7

Stack Overflow用户

发布于 2021-01-05 16:49:14

只是我自己遇到了这个问题,想把我的解决办法发出去。

我们需要将True/False数组返回到工作表函数。为此,我创建了一个函数,该函数接受一个2D数组、列所需的值以及要比较的值。然后返回所需的True/False的2d单列数组。

代码语言:javascript
运行
复制
Function myeval(arr() As Variant, clm As Long, vl As Variant) As Variant()
    Dim temp() As Variant
    ReDim temp(1 To UBound(arr, 1), 1 To 1)
    
    Dim i As Long
    For i = 1 To UBound(arr, 1)
        temp(i, 1) = arr(i, clm) = vl
    Next i
    
    myeval = temp
End Function

因此,在这一特殊情况下,它将被称为:

代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Variant
    MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), myeval(Range("LevelMonsters").Value, 1, level),"""")
End Function
票数 7
EN

Stack Overflow用户

发布于 2021-01-05 18:22:53

通过VBA避免工作表函数中的类型不匹配

请记住,第二个参数反映了一个完全基于工作表逻辑(返回0或1个单元格值/False或True)的动态矩阵条件)。

  • 至少在此参数内执行计算,并且
  • 将函数类型(显式或隐式)声明为Variant
代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Variant
    ''   Failing assignment:
    '    MonstersInLevel = Application.WorksheetFunction.Filter(Range("LevelMonsters").Columns(2), _
    '        Range("LevelMonsters").Columns(1) = level _
    '        )
    MonstersInLevel = Application.WorksheetFunction.Filter( _
                      Range("LevelMonsters").Columns(2), _
                      Evaluate(Range("LevelMonsters").Columns(1).Address & "=" & level) _
                      )
End Function

求完备函数的...or

代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Variant
    Dim expr As String
    expr = "=Filter(" & _
           Range("LevelMonsters").Columns(2).Address & "," & _
           Range("LevelMonsters").Columns(1).Address & "=" & level & _
           ")"
    'Debug.Print expr
    MonstersInLevel = Evaluate(expr)
End Function

示例调用将结果写入任何目标

代码语言:javascript
运行
复制
Dim v
v = MonstersInLevel(2)
Sheet1.Range("D2").Resize(UBound(v), UBound(v, 2)) = v

当然,也可以以编程方式编写.Formula2表达式,甚至可以拆分为溢出范围引用。

增编.//截至1月10日

通过()向后兼容解决方案

“如果你们知道比Application.WorksheetFunction.Filter更合适的其他VBA函数,我会没事的。”

为了提供一个向后兼容的替代方案,我演示了基于先前匹配结果(参见Filter())的经典(VBA.)[3]函数(参见[1])的以下方法。

注意,Application.Match()比较了两个(!)数组输入提供了整个可能的结果数组(而不是最频繁执行的单个结果)。非发现由-1-1值标识;将+1结果添加到一组0和1中。[2]部分为阳性结果输入了相应的数据。最终,非发现(即0或零)被一个棘手的负面过滤删除。

getLevels() 函数

代码语言:javascript
运行
复制
Function getLevels(rng As Range, ByVal level As Long)
'Site: https://stackoverflow.com/questions/65630126/how-to-remove-only-the-duplicate-row-instead-of-removing-all-the-rows-that-follo
    '[0] get datafield array
    Dim v, v2
    v = Application.Index(rng.Value2, 0, 1)     ' 1st column
    v2 = Application.Index(rng.Value2, 0, 2)        ' 2nd column
    '[1] check data (with Match comparing 2 arrays :-)
    Dim results
    results = Application.Transpose(Application.Match(v, Array(level), 0))
    '[2] rebuild with False/True entries
    Dim i As Long
    For i = 1 To UBound(results)
        results(i) = IsError(results(i)) + 1        ' 0 or 1-values
        If results(i) Then results(i) = v2(i, 1)    ' get current value if true
    Next i
    '[3] remove zeros (negative filtering)
    results = Filter(results, "0", False)
    '[4] return results as vertical 1-based array
    getLevels = Application.Transpose(results)
End Function

示例调用

代码语言:javascript
运行
复制
    Const LVL = 2       ' define level
    With Sheet1                                     ' change to project's sheet Code(Name)
        'define data range (assuming columns A:B)
        Dim rng As Range
        Set rng = .UsedRange.Resize(, 2)
        'function call getLevels()
        Dim levels
        levels = getLevels(rng, level:=LVL)
        'write to target
        .Columns("I:I").Clear
        .Range("I2").Resize(UBound(levels), 1) = levels
    End With
票数 4
EN

Stack Overflow用户

发布于 2021-01-11 17:02:34

没有任何支持VBA功能的解决方案:

代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Variant
    With Application.WorksheetFunction
        MonstersInLevel = .Filter(Range("LevelMonsters").Columns(2), _
        .IfError(.XLookup(Range("LevelMonsters").Columns(1), level, True), False))
    End With
End Function

XLookup返回一个#N/ATrue数组。IfError用False替换错误。最后,Filter函数接收作为第二个参数的布尔数组。

编辑

由于@ScottCraner,删除了IfError函数:

代码语言:javascript
运行
复制
Function MonstersInLevel(level As Integer) As Variant
    With Application.WorksheetFunction
        MonstersInLevel = .Filter(Range("LevelMonsters").Columns(2), _
        .XLookup(Range("LevelMonsters").Columns(1), level, True, False))
    End With
End Function
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62206989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档