在Excel VBA中过滤2D数组

tho*_*mad 5 arrays excel vba filter multidimensional-array

使用Excel和VBA,我想要一些关于如何最好地使用VBA过滤数组中的数据(与人们可能使用数据透视表的方式相同)的建议.我正在创建一个UserForm,它将根据当前存在的数据做出一些数据决策.我可以想象如何做得好,但我不熟悉VBA编程.

这是一个例子

A       B       C
bob     12      Small
sam     16      Large
sally   1346    Large
sam     13      Small
sally   65      Medium
bob     1       Medium
Run Code Online (Sandbox Code Playgroud)

要获取数组中的数据,我可以使用

Dim my_array As Variant

my_array = Range("A1").CurrentRegion
Run Code Online (Sandbox Code Playgroud)

现在,我熟悉循环2D数组,但我想知道:过滤二维数组数据的最有效方法是什么(没有时间循环遍历数组)?

例如,我如何得到这样的数据:

data_for_sally As Variant 'rows with sally as name in ColA
data_for_sally_less_than_ten As Variant ' all rows with sally's name in ColA and colB < 10
data_for_all_mediums as Variant ' all rows where ColC is Medium
Run Code Online (Sandbox Code Playgroud)

建议?我可以使用一堆自定义函数和循环来解决这个问题,但我认为必须有更好的方法.谢谢.

ass*_*ias 5

我假设您只想使用VBA.

我认为这取决于几个参数,主要是:

  • 你运行相同条件的频率=>你存储过滤器的结果还是每次重新计算?
  • 你需要多长时间来过滤一下东西=>如果经常的话,值得拥有一个合适的代码结构,如果没有,那么一个关闭循环显然是要走的路.

从OO的角度来看,假设性能(速度和内存)不是问题,我会采用以下设计(我不会详细介绍实现,只给出一般的想法).创建一个你可以像这样使用的类(让我们称它为富有想象力的ArrayFilter).

设置过滤器

Dim filter As New ArrayFilter
With filter
    .name = "sam"
    .category = "Medium"
    .maxValue = 10
End With
Run Code Online (Sandbox Code Playgroud)

要么

filter.add(1, "sam") 'column 1
filter.add(3, "Medium") 'column 3
filter.addMax(2, 10) 'column 2
Run Code Online (Sandbox Code Playgroud)

创建过滤的数据集

filteredArray = getFilteredArray(originalArray, filter)
Run Code Online (Sandbox Code Playgroud)

getFilteredArray编写起来相当简单:在数组上循环检查值是否与过滤器匹配并将有效行放在新数组中:

If filter.isValidLine(originalArray, lineNumber) Then 'append to new array
Run Code Online (Sandbox Code Playgroud)

优点

  • 干净的设计
  • 可重用,尤其是使用列号的第二个版本.这可以用来真正过滤任何数组.
  • 过滤代码在一个可以测试的函数中
  • 推论:避免重复代码

缺点

  • 即使您使用相同的过滤器两次,也会每次重新计算过滤.例如,您可以将结果存储在字典中 - 请参阅下文.
  • 内存:每次调用getFilteredArray都会创建一个新数组,但不知道如何才能避免这种情况
  • 这增加了很多行代码,所以只有当它有助于使代码更易于阅读/维护时,我才会这样做.

ps:如果需要缓存结果以提高性能,一种方法是将结果存储在字典中并向getFilteredArray函数添加一些逻辑.请注意,除非您的数组非常大并且/或者您经常运行相同的过滤器,否则这可能不值得.

filters.add filter, filteredArray 'filters is a dictionary
Run Code Online (Sandbox Code Playgroud)

这样,下次调用getFilteredArray时,可以执行以下操作:

For each f in filters
    'Check if all conditions in f and newFilter are the same
    'If they are:
    getFilteredArray = filters(f)
    Exit Function
Next

'Not found in cache: compute the result
Run Code Online (Sandbox Code Playgroud)