Excel 在VBA中获取列的所有唯一值的更快方法?
有没有更快的方法Excel 在VBA中获取列的所有唯一值的更快方法?,excel,vba,Excel,Vba,有没有更快的方法 Set data = ws.UsedRange Set unique = CreateObject("Scripting.Dictionary") On Error Resume Next For x = 1 To data.Rows.Count unique.Add data(x, some_column_number).Value, 1 Next x On Error GoTo 0 在这里,代码>唯一。键< /Cord>得到我需要的,但是对于拥有成千上万个记录
Set data = ws.UsedRange
Set unique = CreateObject("Scripting.Dictionary")
On Error Resume Next
For x = 1 To data.Rows.Count
unique.Add data(x, some_column_number).Value, 1
Next x
On Error GoTo 0
在这里,<>代码>唯一。键< /Cord>得到我需要的,但是对于拥有成千上万个记录的文件来说,循环本身似乎非常慢(但这在Python或C++中是一个根本不成问题的问题)。< p>加载数组中的值会快得多:
Dim data(), dict As Object, r As Long
Set dict = CreateObject("Scripting.Dictionary")
data = ActiveSheet.UsedRange.Columns(1).Value
For r = 1 To UBound(data)
dict(data(r, some_column_number)) = Empty
Next
data = WorksheetFunction.Transpose(dict.keys())
你也应该考虑脚本的早期绑定。字典:
Dim dict As New Scripting.Dictionary ' requires `Microsoft Scripting Runtime` '
请注意,使用字典要比使用大型数据集快得多
作为奖励,这里有一个类似于从2D阵列中删除重复项的过程:
Public Sub RemoveDuplicates(data, ParamArray columns())
Dim ret(), indexes(), ids(), r As Long, c As Long
Dim dict As New Scripting.Dictionary ' requires `Microsoft Scripting Runtime` '
If VarType(data) And vbArray Then Else Err.Raise 5, , "Argument data is not an array"
ReDim ids(LBound(columns) To UBound(columns))
For r = LBound(data) To UBound(data) ' each row '
For c = LBound(columns) To UBound(columns) ' each column '
ids(c) = data(r, columns(c)) ' build id for the row
Next
dict(Join$(ids, ChrW(-1))) = r ' associate the row index to the id '
Next
indexes = dict.Items()
ReDim ret(LBound(data) To LBound(data) + dict.Count - 1, LBound(data, 2) To UBound(data, 2))
For c = LBound(ret, 2) To UBound(ret, 2) ' each column '
For r = LBound(ret) To UBound(ret) ' each row / unique id '
ret(r, c) = data(indexes(r - 1), c) ' copy the value at index '
Next
Next
data = ret
End Sub
试试这个
Option Explicit
Sub UniqueValues()
Dim ws As Worksheet
Dim uniqueRng As Range
Dim myCol As Long
myCol = 5 '<== set it as per your needs
Set ws = ThisWorkbook.Worksheets("unique") '<== set it as per your needs
Set uniqueRng = GetUniqueValues(ws, myCol)
End Sub
Function GetUniqueValues(ws As Worksheet, col As Long) As Range
Dim firstRow As Long
With ws
.Columns(col).RemoveDuplicates Columns:=Array(1), header:=xlNo
firstRow = 1
If IsEmpty(.Cells(1, col)) Then firstRow = .Cells(1, col).End(xlDown).row
Set GetUniqueValues = Range(.Cells(firstRow, col), .Cells(.Rows.Count, col).End(xlUp))
End With
End Function
选项显式
子唯一值()
将ws设置为工作表
调光范围
暗霉
myCol=5'使用Excel的AdvancedFilter函数执行此操作。
使用Excel内置C++是用较小的数据集最快的方式,使用字典对于较大的数据集更快。例如:
复制A列中的值并在B列中插入唯一值:
Range("A1:A6").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("B1"), Unique:=True
它也适用于多个列:
Range("A1:B4").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("D1:E1"), Unique:=True
请注意多列,因为它并不总是按预期工作。在这些情况下,我求助于删除重复项,这是通过选择列来实现的。参考:
在这里,我将基于第三列删除重复列:
Range("A1:C4").RemoveDuplicates Columns:=3, Header:=xlNo
Range("A1:C4").RemoveDuplicates Columns:=Array(2, 3), Header:=xlNo
在这里,我删除了基于第二列和第三列的重复列:
Range("A1:C4").RemoveDuplicates Columns:=3, Header:=xlNo
Range("A1:C4").RemoveDuplicates Columns:=Array(2, 3), Header:=xlNo
PowerShell是一个非常强大和高效的工具。这有点作弊,但通过VBA炮击PowerShell会带来很多选择
下面的大部分代码只是将当前工作表保存为csv文件。输出是另一个仅具有唯一值的csv文件
Sub AnotherWay()
Dim strPath As String
Dim strPath2 As String
Application.DisplayAlerts = False
strPath = "C:\Temp\test.csv"
strPath2 = "C:\Temp\testout.csv"
ActiveWorkbook.SaveAs strPath, xlCSV
x = Shell("powershell.exe $csv = import-csv -Path """ & strPath & """ -Header A | Select-Object -Unique A | Export-Csv """ & strPath2 & """ -NoTypeInformation", 0)
Application.DisplayAlerts = True
End Sub
这很有趣,因为我不得不一遍又一遍地阅读这些说明,但它认为我找到了一种更快的方法:
Set data = ws.UsedRange
dim unique as variant
unique = WorksheetFunction.Unique(data)
然后,您可以使用unique
数组执行任何操作,例如迭代它:
For i = LBound(unique) To UBound(unique)
Range("Q" & i) = indexes(i, 1)
Next
您需要添加参考“Microsoft脚本运行时”,我已经添加了它。它似乎找不到“.Dictionary”中的“Scripting”似乎并不重要,即使是后期绑定,它也能在一眨眼之间运行。为什么那个代码比我的要快得多?用excel一个单元格一个单元格地读很慢。加载数组中的数据并在必要时将其写回会更快。@MGae2M,使用字典上的.Keys()
来获取数组中的唯一值。这太棒了!2个问题#1-这是将数据粘贴到工作表中,而不是将其保存在VBA变量中#2-它查看的是公式,而不是实际值(对我来说,不是在列中粘贴唯一值,而是只将一个常用公式粘贴到一个单元格中)。@ZygD 1。范围是一个变量,您可以在VBA中使用它。2.如果做得不对,请使用“粘贴”作为值,而不是在公式1上进行粘贴。即使从技术上讲,范围是一个变量。。。但问题是,您不能使用AdvancedFilter
方法仅将数据放入“VBA可见”变量,如数组或字典(即工作表中不存在“物理”变量)。2.我找不到怎么做,这个AdvancedFilter
方法真的提供了粘贴为值的选项吗?问题#3-这个方法删除了工作表中的原始筛选器(如果存在)。AdvancedFilter
不是最快的方法。在大数据集上,使用字典的性能要优于高级过滤器(对于100k单元格,大约500毫秒而不是60秒)。这是一个好方法。但是需要注意的是,这会修改原始的源列。此函数仅在Office 365中可用。我想谢谢,使用此解决方案,您可以在一个列中返回唯一值数组,只需一行代码:unique=WorksheetFunction.unique(列(1))
这是一个强大的代码:但愿我早知道这一点:)