用于存储和计数唯一ID的多维数组

时间:2019-03-07 19:28:14

标签: excel vba

背景

在试图更好地理解动态多维数组时,我试图构建一个以捕获唯一值并计算唯一值的出现次数(我应该能够使用countif迅速验证这一点)。

在阅读有关尝试重新保存多维数组的imim时,我读到只能重新对最后一个参数进行imim,因此我尝试设置2个参数,其中第一个是唯一值,第二个是计数:arr(2,k)。如果我的理解是错误的,那也很重要。

我将把数组的最终输出放入第3列(唯一ID)和第4列(出现的次数)。


问题:

将值添加到数组时,我无法收集所有唯一值。我已经能够收集3个唯一值,当数据中有6个,并且每个值的出现都停留在1时,例如,不进行迭代。


问题:

很抱歉,这实际上是2个问题...

  • 1)我是否使用redim保持器arr(2,0至k)适当的语法?

  • 2)动态数组生成是否存在明显问题,这可以解释为什么我没有捕获所有唯一值?

我可能会问三分之一为什么我无法使发生次数起作用,但是我希望,如果我理解了上述问题,我有望在这一部分中奋斗。


数据如下:

所有数据都在A列中

cat
dog
mouse
cat
mouse
bear
frog
cat
moose
cat
dog

有问题的代码:

Option Explicit

Private Sub unique_arr()
    Dim arr As Variant, i As Long, lr As Long, k As Long
    lr = Cells(Rows.Count, 1).End(xlUp).Row
    ReDim arr(2, k)
    For i = 1 To lr
        If Application.IfError(Application.Match(Cells(i, 1).Value, arr, 0), 0) = 0 Then
            ReDim Preserve arr(2, 0 To k)
            arr(1, k) = Cells(i, 1).Value
            arr(2, k) = 1
            k = k + 1
        Else
            arr(2, Application.Match(Cells(i, 1), arr(1), 0)) = arr(2, Application.Match(Cells(i, 1), arr(1), 0)) + 1
        End If
    Next i
    For i = LBound(arr) To UBound(arr)
        Cells(i + 1, 3).Value = arr(1, i)
        Cells(i + 1, 4).Value = arr(2, i)
    Next i
End Sub

2 个答案:

答案 0 :(得分:5)

虽然总的来说最好用字典,但If比较还是有一些问题。

If Application.IfError(Application.Match(Cells(i, 1).Value, arr, 0), 0) = 0 Then

VBA有其自己的IsError,它返回True / False。

If IsError(Application.Match(Cells(i, 1).Value, arr, 0), 0)) Then

另外,arr是二维数组;本质上,它既有行又有列。工作表的“匹配”只能在单列或单行上工作。您需要通过“索引”来“分割”您想要的内容。

If Not IsError(Application.Match(Cells(i, 1).Value, application.index(arr, 1, 0), 0), 0)) Then

最后, arr 被定义为ReDim arr(2, k)。这使其成为arr(0 to 2, 0 to k),因此,第一排中有三个元素( 0、1、2 ),而不是2。您实际上从未在第一排中使用0。应该是

k = 1
ReDim arr(1 to 2, 1 to k)

将其全部缠绕起来,最终得到的是这样的东西。

Option Explicit

Private Sub unique_arr()
    Dim i As Long, lr As Long, k As Long, arr As Variant, m As Variant

    'assign values to some vars
    lr = Cells(Rows.Count, 1).End(xlUp).Row
    k = 1
    ReDim arr(1 To 2, 1 To k)

    'loop through cells, finding duplicates and counting
    For i = 1 To lr
        m = Application.Match(Cells(i, 1).Value, Application.Index(arr, 1, 0), 0)
        If IsError(m) Then
            ReDim Preserve arr(1 To 2, 1 To k)
            arr(1, k) = Cells(i, 1).Value
            arr(2, k) = 1
            k = k + 1
        Else
            arr(2, m) = arr(2, m) + 1
        End If
    Next i

    'loop through array's second rank
    For i = LBound(arr, 2) To UBound(arr, 2)
        Cells(i, 3).Value = arr(1, i)
        Cells(i, 4).Value = arr(2, i)
    Next i

End Sub

答案 1 :(得分:2)

对于这样的事情,我会像这样使用字典:

Sub ExtractUniqueCounts()

    Dim ws As Worksheet
    Dim rCell As Range
    Dim hUnq As Object

    Set ws = ActiveWorkbook.ActiveSheet
    Set hUnq = CreateObject("Scripting.Dictionary") 'Create Dictionary object

    'Loop through populated cells in column A
    For Each rCell In ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)).Cells
        'Ignore blanks
        If Len(rCell.Value) > 0 Then
            'Check if this is a new, unique value that hasn't been added yet
            If Not hUnq.Exists(rCell.Value) Then
                'New unique value found, add to dictionary and set count to 1
                hUnq(rCell.Value) = 1
            Else
                'Not a unique value, increase existing count
                hUnq(rCell.Value) = hUnq(rCell.Value) + 1
            End If
        End If
    Next rCell

    'Check if there are any results
    If hUnq.Count > 0 Then
        'Results found
        'Output the keys (unique values)
        ws.Range("C1").Resize(hUnq.Count).Value = Application.Transpose(hUnq.keys)

        'Output the values of the keys (the counts in this case)
        ws.Range("D1").Resize(hUnq.Count).Value = Application.Transpose(hUnq.items)
    Else
        'No results, return error
        MsgBox "No data"
    End If

End Sub