真正需要的所有代码都只是几行代码:
Sub test()
Dim arr As Variant: arr = Array("A", "A", "C", "D", "A", "E", "G")
With Application
uniques = .Index(arr, 1, Filter(.IfError(.Match(.Transpose(.Evaluate("ROW(1:" & UBound(.Match(arr, arr, 0)) & ")")), .Match(arr, arr, 0), 0), "|"), "|", False))
End With
End Sub
上面将返回一个一维数组,返回我们原始数组中的所有唯一元素:
说明:
检索所有这些值的行看起来很密集,所以让我们把它分成几部分:
Application.Match 能够在其参数中使用数组。所以基本上我们在看:.Match({"A","A","C","D","A","E","G"},{"A","A","C","D","A","E","G"},0)。然后返回的数组将是:{1,1,3,4,1,6,7},这实际上是找到每个值的第一个位置。这一结果将成为我们进一步发展的基础。
我们可以在我们的代码中看到第三个.Match,我们基本上需要告诉以下内容:.Match({1,2,3,4,5,6,7},{1,1,3,4,1,6,7},0)。第一个参数是上面高亮代码检索到的。
.Evaluate("ROW(1:" & UBound(.Match(arr, arr, 0)) & ")") 将返回来自 1-7 的值数组,Application.Transpose 将返回一维数组。
最后一步将返回一个包含错误的数组,但是代码不会中断,因为我们使用的是Application 而不是WorksheetFunction。结果数组看起来像{1,Error 2042,3,4,Error 2042,6,7}。现在的重点是摆脱 Error 值。
这样做的方法是通过Application.IfError,它将评估数组并将所有错误值更改为给定的字符串值。在我们的例子中,我使用了管道符号。由用户决定一个足够独特的符号,它不会出现在原始数组的任何元素中。所以经过评估。我们当前的数组看起来像:{1,|,3,4,|,6,7}。
现在我们检索了一个带有管道符号的数组,我们希望它们出来!一个快速的方法是使用Filter 函数。 Filter 返回一个包含或不包含符合我们条件的元素的数组(取决于第三个参数中的 TRUE 或 FALSE)。
所以基本上我们想要返回一个像这样的数组:Filter(<array>, "|", False)。生成的一维数组现在看起来像:{1,3,4,6,7}。
在这一点上我们有点。我们只需要从原始数组中切出正确的值。为此,我们可以使用Application.Index。我们只想告诉.Index 我们对哪些行感兴趣。为此,我们可以加载我们之前找到的一维数组。所以代码看起来像:.Index(arr1, <array>, 1) 这将产生一个一维数组:{"A","C","D","E","G"}
结论:
你有它。一行(不仅仅是一个操作)从另一个一维数组没有迭代检索唯一值的一维数组。此代码可用于任何以arr 声明的一维数组。
有用吗?我不是 100% 确定,但我终于达到了我在项目中尝试的目标。生成的数组可以立即用于您需要在其中使用唯一值的任何任务中。
比较:字典与 Application.Methods:
对Range(A1:A50000)中的随机项进行比较,性能确实受到了打击。特此迭代字典与非迭代 Application.Methods 方法在 1000 个项目步骤中的时间比较。在 1000 项和每 10000 项标记的结果下方(以秒为单位):
| Items | Dictionary | Methods |
|------- |------------ |------------- |
| 1000 | 0,02 | 0,03 |
| 10000 | 0 | 0,88 |
| 20000 | 0,02 | 3,31 |
| 30000 | 0,02 | 7,3 |
| 40000 | 0,02 | 12,84 |
| 50000 | 0,03 | 20,2 |
使用的Dictionary 方法:
Sub Test()
Dim arr As Variant: arr = Application.Transpose(Range("A1:A50000"))
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim x As Long
For x = LBound(arr) To UBound(arr)
dict(arr(x)) = 1
Next x
Dim uniques As Variant: uniques = dict.Keys
End Sub
结论: 与更常见的Dictionary 做法相比,此方法最多可处理 1000 个项目,其处理时间大致相等。在任何更大的事情上,迭代(通过内存)总是会击败方法方法!
我敢肯定,@ScottCraner 的 shown 等新动态数组函数会更加限制处理时间。