计算数组中的值 VBA
Counting Values in Array VBA
我有两个数组:Arr1 有 11 个值,有些重复,有些不重复,Arr2 包含与 Arr1 相同的值,只是没有重复值。本想用 Countif 函数来计算 Arr2 中的值在 Arr1 中出现了多少次,但我知道 countif 不适用于数组。
Arr1 包含 = A,A,B,C,A,D,E,E,F,F,G
Arr2 包含 = A,B,C,D,E,F,G
理想情况下,代码会在一列中输出 Array2,在另一列中输出相应的计数,如下所示:
Col R Col S
A 3
B 1
C 1
D 1
E 2
F 2
G 1
这是我编写的有效代码,但仅适用于一个值:
Cells(1, 18).Resize(UBound(Arr2)).Value = Application.Transpose(Arr2)
Dim count As Integer
Dim i As Double
For i = 1 To 7
count = count + Abs(Arr1(i) = "A")
Next i
Range("S1") = count
如果我尝试通过添加数组来遍历数据,我会收到“超出范围”错误。
Cells(1, 18).Resize(UBound(Arr2)).Value = Application.Transpose(Arr2)
Dim count As Integer
Dim i As Double
For i = 1 To 7
count = count + Abs(Arr1(i) = Arr2(i))
Cells(i, "S") = count
Next i
我不太确定我哪里出错了,我假设添加 Arr2 是问题所在,因此非常感谢任何关于如何修复它的建议!
谢谢!
您需要第三个数组(您也可以使用范围)作为结果和两个嵌套的 for 循环。
这是一个例子
Sub TestA()
Dim A1(), A2(), A3(), A As Variant, B As Variant
Dim I As Long
A1 = Array(1, 2, 1, 2, 3, 3, 3, 4, 5, 5, 6)
A2 = Array(1, 2, 3, 4, 5, 6)
ReDim A3(LBound(A2) To UBound(A2))
I = LBound(A2)
For Each A In A2
For Each B In A1
A3(I) = A3(I) + IIf(A = B, 1, 0)
Next B
I = I + 1
Next A
End Sub
您可以在此处使用 scripting.dictionary。这样一来,您只需要使用第一个数组,而无需使用第二个数组。请参阅下面的代码片段:
Option Explicit
Sub count_array()
Dim arr As Variant
Dim i As Integer
Dim dict As Scripting.Dictionary
Dim k
' specify array
arr = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
' loop through records and increment for each instance
Set dict = New Scripting.Dictionary
For i = LBound(arr) To UBound(arr)
If Not dict.Exists(arr(i)) Then
dict.Add arr(i), 1
Else
dict(arr(i)) = dict(arr(i)) + 1
End If
Next i
' how to loop through each key
For Each k In dict
Debug.Print k, dict(k)
Next k
End Sub
请记住在“工具”>“参考”下添加“Microsoft Scripting Runtime”参考。这将输出:
A 3
B 1
C 1
D 1
E 2
F 2
G 1
您可以使用字典来提取唯一列表并跟踪计数。
在下面的代码中,我从工作表范围创建了 VBA 数组,但您也可以直接轻松地创建它:
例如:Array("A","A","B","C","A","D","E","E","F","F","G")
如果这是在工作表上,您可以只使用公式来创建列。
Option Explicit
Function countIt(rg1 As Range)
Dim v, w
Dim D As Object
Set D = CreateObject("Scripting.Dictionary")
D.CompareMode = TextCompare
v = rg1
For Each w In v
If Not D.Exists(w) Then
D.Add w, 1
Else
D(w) = D(w) + 1
End If
Next w
Dim x, I As Long
ReDim x(1 To D.Count, 1 To 2)
For Each w In D.Keys
I = I + 1
x(I, 1) = w
x(I, 2) = D(w)
Next w
countIt = x
End Function
唯一词典
第一个代码执行您要求的操作,但第二个代码在没有第二个数组的情况下执行此操作。两种解决方案各有利弊。
代码
Option Explicit
Sub writeUniqueWithCount()
Const tgtName As String = "Sheet1"
Const tgtFirstCell As String = "A1"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Arr1 As Variant
Arr1 = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim j As Long
For j = LBound(Arr1) To UBound(Arr1)
dict(Arr1(j)) = dict(Arr1(j)) + 1
Next
Dim Arr2 As Variant
Arr2 = Array("A", "B", "C", "D", "E", "F", "G")
Dim NoE2 As Long
NoE2 = UBound(Arr2) - LBound(Arr2) + 1
Dim RowOffset As Long
RowOffset = 1 - LBound(Arr2)
Dim Result As Variant
ReDim Result(1 To NoE2, 1 To 2)
Dim i As Long
For i = 1 To NoE2
Result(i, 1) = Arr2(i - RowOffset)
Result(i, 2) = dict(Result(i, 1))
Next i
Dim rng As Range
Set rng = wb.Worksheets(tgtName).Range(tgtFirstCell)
rng.Resize(UBound(Result, 1), UBound(Result, 2)).Value = Result
MsgBox "Wrote unique."
End Sub
Sub writeUniqueWithCountOneArray()
Const tgtName As String = "Sheet1"
Const tgtFirstCell As String = "A1"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Arr1 As Variant
Arr1 = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim j As Long
For j = LBound(Arr1) To UBound(Arr1)
dict(Arr1(j)) = dict(Arr1(j)) + 1
Next
Dim Result As Variant
ReDim Result(1 To dict.Count, 1 To 2)
Dim Key As Variant
Dim i As Long
For Each Key In dict.Keys
i = i + 1
Result(i, 1) = Key
Result(i, 2) = dict(Key)
Next Key
Dim rng As Range
Set rng = wb.Worksheets(tgtName).Range(tgtFirstCell)
rng.Resize(UBound(Result, 1), UBound(Result, 2)).Value = Result
MsgBox "Wrote unique."
End Sub
编译频率计数最好用 Scripting.DIctionary
Dim myFreq as Scripting.Dictionary
Set myFreq = New Scripting.Dictionary
Dim myKey as Variant
For each myKey in Split("A,A,B,C,A,D,E,E,F,F,G",",")
If not myFreq.Exists(myKey) then
myFreq.Add myKey,1
else
myFreq.Item(myKey)=myFreq.Item(myKey)+1
End if
Next
然后您可以遍历第二个数组来检查
For each myKey in SPlit("A,B,C,D,E,F,G",",")
If MyFreq.Exists(myKey) then
Debug.Print myKey, myFreq.Item(mykey)
Else
Debug.Print myKey,0
end if
Next
我有两个数组:Arr1 有 11 个值,有些重复,有些不重复,Arr2 包含与 Arr1 相同的值,只是没有重复值。本想用 Countif 函数来计算 Arr2 中的值在 Arr1 中出现了多少次,但我知道 countif 不适用于数组。
Arr1 包含 = A,A,B,C,A,D,E,E,F,F,G
Arr2 包含 = A,B,C,D,E,F,G
理想情况下,代码会在一列中输出 Array2,在另一列中输出相应的计数,如下所示:
Col R Col S
A 3
B 1
C 1
D 1
E 2
F 2
G 1
这是我编写的有效代码,但仅适用于一个值:
Cells(1, 18).Resize(UBound(Arr2)).Value = Application.Transpose(Arr2)
Dim count As Integer
Dim i As Double
For i = 1 To 7
count = count + Abs(Arr1(i) = "A")
Next i
Range("S1") = count
如果我尝试通过添加数组来遍历数据,我会收到“超出范围”错误。
Cells(1, 18).Resize(UBound(Arr2)).Value = Application.Transpose(Arr2)
Dim count As Integer
Dim i As Double
For i = 1 To 7
count = count + Abs(Arr1(i) = Arr2(i))
Cells(i, "S") = count
Next i
我不太确定我哪里出错了,我假设添加 Arr2 是问题所在,因此非常感谢任何关于如何修复它的建议! 谢谢!
您需要第三个数组(您也可以使用范围)作为结果和两个嵌套的 for 循环。 这是一个例子
Sub TestA()
Dim A1(), A2(), A3(), A As Variant, B As Variant
Dim I As Long
A1 = Array(1, 2, 1, 2, 3, 3, 3, 4, 5, 5, 6)
A2 = Array(1, 2, 3, 4, 5, 6)
ReDim A3(LBound(A2) To UBound(A2))
I = LBound(A2)
For Each A In A2
For Each B In A1
A3(I) = A3(I) + IIf(A = B, 1, 0)
Next B
I = I + 1
Next A
End Sub
您可以在此处使用 scripting.dictionary。这样一来,您只需要使用第一个数组,而无需使用第二个数组。请参阅下面的代码片段:
Option Explicit
Sub count_array()
Dim arr As Variant
Dim i As Integer
Dim dict As Scripting.Dictionary
Dim k
' specify array
arr = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
' loop through records and increment for each instance
Set dict = New Scripting.Dictionary
For i = LBound(arr) To UBound(arr)
If Not dict.Exists(arr(i)) Then
dict.Add arr(i), 1
Else
dict(arr(i)) = dict(arr(i)) + 1
End If
Next i
' how to loop through each key
For Each k In dict
Debug.Print k, dict(k)
Next k
End Sub
请记住在“工具”>“参考”下添加“Microsoft Scripting Runtime”参考。这将输出:
A 3
B 1
C 1
D 1
E 2
F 2
G 1
您可以使用字典来提取唯一列表并跟踪计数。
在下面的代码中,我从工作表范围创建了 VBA 数组,但您也可以直接轻松地创建它:
例如:Array("A","A","B","C","A","D","E","E","F","F","G")
如果这是在工作表上,您可以只使用公式来创建列。
Option Explicit
Function countIt(rg1 As Range)
Dim v, w
Dim D As Object
Set D = CreateObject("Scripting.Dictionary")
D.CompareMode = TextCompare
v = rg1
For Each w In v
If Not D.Exists(w) Then
D.Add w, 1
Else
D(w) = D(w) + 1
End If
Next w
Dim x, I As Long
ReDim x(1 To D.Count, 1 To 2)
For Each w In D.Keys
I = I + 1
x(I, 1) = w
x(I, 2) = D(w)
Next w
countIt = x
End Function
唯一词典
第一个代码执行您要求的操作,但第二个代码在没有第二个数组的情况下执行此操作。两种解决方案各有利弊。
代码
Option Explicit
Sub writeUniqueWithCount()
Const tgtName As String = "Sheet1"
Const tgtFirstCell As String = "A1"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Arr1 As Variant
Arr1 = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim j As Long
For j = LBound(Arr1) To UBound(Arr1)
dict(Arr1(j)) = dict(Arr1(j)) + 1
Next
Dim Arr2 As Variant
Arr2 = Array("A", "B", "C", "D", "E", "F", "G")
Dim NoE2 As Long
NoE2 = UBound(Arr2) - LBound(Arr2) + 1
Dim RowOffset As Long
RowOffset = 1 - LBound(Arr2)
Dim Result As Variant
ReDim Result(1 To NoE2, 1 To 2)
Dim i As Long
For i = 1 To NoE2
Result(i, 1) = Arr2(i - RowOffset)
Result(i, 2) = dict(Result(i, 1))
Next i
Dim rng As Range
Set rng = wb.Worksheets(tgtName).Range(tgtFirstCell)
rng.Resize(UBound(Result, 1), UBound(Result, 2)).Value = Result
MsgBox "Wrote unique."
End Sub
Sub writeUniqueWithCountOneArray()
Const tgtName As String = "Sheet1"
Const tgtFirstCell As String = "A1"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Arr1 As Variant
Arr1 = Array("A", "A", "B", "C", "A", "D", "E", "E", "F", "F", "G")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim j As Long
For j = LBound(Arr1) To UBound(Arr1)
dict(Arr1(j)) = dict(Arr1(j)) + 1
Next
Dim Result As Variant
ReDim Result(1 To dict.Count, 1 To 2)
Dim Key As Variant
Dim i As Long
For Each Key In dict.Keys
i = i + 1
Result(i, 1) = Key
Result(i, 2) = dict(Key)
Next Key
Dim rng As Range
Set rng = wb.Worksheets(tgtName).Range(tgtFirstCell)
rng.Resize(UBound(Result, 1), UBound(Result, 2)).Value = Result
MsgBox "Wrote unique."
End Sub
编译频率计数最好用 Scripting.DIctionary
Dim myFreq as Scripting.Dictionary
Set myFreq = New Scripting.Dictionary
Dim myKey as Variant
For each myKey in Split("A,A,B,C,A,D,E,E,F,F,G",",")
If not myFreq.Exists(myKey) then
myFreq.Add myKey,1
else
myFreq.Item(myKey)=myFreq.Item(myKey)+1
End if
Next
然后您可以遍历第二个数组来检查
For each myKey in SPlit("A,B,C,D,E,F,G",",")
If MyFreq.Exists(myKey) then
Debug.Print myKey, myFreq.Item(mykey)
Else
Debug.Print myKey,0
end if
Next