arrays - VBA动态数组错误地复制某些值

标签 arrays vba excel dynamic-arrays

我想以此作为序言,我不知道为什么我的代码正在做它正在做的事情。我真的希望这里的 VBA 专家之一能够提供帮助。另外,这是我的第一篇文章,所以我尽力遵守规则,但如果我做错了什么,请指出。


我有一个子程序,它循环访问一列数据并创建一个数组。它调用一个函数来检查特定值是否已在数组中。如果不是,则重新调整数组的大小,插入值,然后再次开始该过程,一直持续到到达列表末尾。我最终得到了一个总共 41 个值的数组,但其中 4 个值被重复了两次,因此数组中只有 37 个唯一值。

我一生都无法弄清楚是什么使这些值与众不同,或者为什么它们被重复。总列表有 700 多个值长,所以我想我应该看到其他重复的值,但我没有。

以下是创建数组的子程序的代码:

Sub ProductNumberArray(strWrkShtName As String, strFindColumn As String, blAsGrp As Boolean, iStart As Integer)
    Dim i As Integer
    Dim lastRow As Integer
    Dim iFindColumn As Integer
    Dim checkString As String

    With wbCurrent.Worksheets(strWrkShtName)
        iFindColumn = .UsedRange.Find(strFindColumn, .Range("A1"), xlValues, xlWhole, xlByColumns).Column
        lastRow = .Cells(Rows.Count, iFindColumn).End(xlUp).row
        For i = iStart To lastRow
            checkString = .Cells(i, iFindColumn).Value
            If IsInArray(checkString, arrProductNumber) = False Then
                If blAsGrp = False Then
                    ReDim Preserve arrProductNumber(0 To j)
                    arrProductNumber(j) = checkString
                    j = j + 1
                Else
                    ReDim Preserve arrProductNumber(1, 0 To j)
                    arrProductNumber(0, j) = .Cells(i, iFindColumn - 1).Value
                    arrProductNumber(1, j) = checkString
                    j = j + 1
                End If
            End If
        Next i
    End With
End Sub

下面是检查 checkString 值是否在数组中的代码:

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
    Dim bDimen As Byte, i As Long

    On Error Resume Next
    If IsError(UBound(arr, 2)) Then bDimen = 1 Else bDimen = 2
    On Error GoTo 0

    Select Case bDimen
    Case 1
        On Error Resume Next
        IsInArray = Application.Match(stringToBeFound, arr, 0)
        On Error GoTo 0
    Case 2
        For i = 1 To UBound(arr, 2)
            On Error Resume Next
            IsInArray = Application.Match(stringToBeFound, Application.Index(arr, , i), 0)
            On Error GoTo 0
            If IsInArray = True Then Exit For
        Next
    End Select
End Function

我们非常欢迎任何帮助。我之前已经能够找到所有问题的答案(或者至少调试并看到一个明显的问题),但是这个问题难倒了我。我希望有人能弄清楚发生了什么事。


[编辑]这是调用子函数的代码:

Sub UpdatePSI()    
    Set wbCurrent = Application.ActiveWorkbook
    Set wsCurrent = wbCurrent.ActiveSheet

    frmWorkbookSelect.Show

    If blFrmClose = True Then 'if the user closes the selection form, the sub is exited
        blFrmClose = False
        Exit Sub
    End If

    Set wsSelect = wbSelect.Sheets(1)

    Call ProductNumberArray("Forecast", "Item", True, 3)

wbCurrentwsCurrentblFrmClose 在通用声明中定义。

最佳答案

到目前为止,对于导致您遇到的重复问题的原因,没有任何(疯狂的)猜测是接近的。这实际上是由您的代码中的错误引起的。

在您的 IsInArray 函数中,您以错误的值完成了数组循环索引。 For i = 1 To UBound(arr, 2) 应为 For i = 1 To UBound(arr, 2) - LBound(arr, 2) + 1。当索引完成一个短路时,这意味着比较字符串永远不会与最后一个数组项进行检查,因此,任何连续相同值中的第二个值将作为重复项进行复制。始终在索引参数中同时使用 LBoundUBound 以避免此类错误和类似类型的错误。


但是,此修复是多余的,因为可以重写该函数以避免完全循环。我还添加了一些其他增强功能:

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
  Dim bDimen As Long
  Dim i As Long

  On Error Resume Next
    bDimen = 2
    If IsError(UBound(arr, 2)) Then bDimen = bDimen - 1
    If IsError(UBound(arr, 1)) Then bDimen = bDimen - 1
  On Error GoTo 0

  Select Case bDimen
    Case 0:
    ' Uninitialized array - return false
    Case 1:
      On Error Resume Next
        IsInArray = Application.Match(stringToBeFound, arr, 0)
      On Error GoTo 0
    Case 2:
      On Error Resume Next
        IsInArray = Application.Match(stringToBeFound, Application.Index(arr, 2), 0)
      On Error GoTo 0
    Case Else
      ' Err.Raise vbObjectError + 666, Description:="Never gets here error."
  End Select
End Function

这是我对字典解决方案的看法:

Public Function ProductNumberDict _
                ( _
                           ByVal TheWorksheet As Worksheet, _
                           ByVal Header As String, _
                           ByVal AsGroup As Boolean, _
                           ByVal Start As Long _
                ) _
        As Scripting.Dictionary

  Set ProductNumberDict = New Scripting.Dictionary
  With TheWorksheet.Rows(1).Cells(WorksheetFunction.Match(Header, TheWorksheet.Rows(1), 0)).EntireColumn
    Dim rngData As Range
    Set rngData = TheWorksheet.Range(.Cells(Start), .Cells(Rows.Count).End(xlUp))
  End With
  Dim rngCell As Range
  For Each rngCell In rngData
    With rngCell
      If Not ProductNumberDict.Exists(.Value2) Then
        ProductNumberDict.Add .Value2, IIf(AsGroup, .Offset(, -1).Value2, vbNullString)
      End If
    End With
  Next rngCell
End Function

以下是如何调用该函数:

Sub UpdatePSI()

  Dim wkstForecast As Worksheet
  Set wkstForecast = ActiveWorkbook.Worksheets("Forecast")

' ...

  Dim dictProductNumbers As Scripting.Dictionary
  Set dictProductNumbers = ProductNumberDict(wkstForecast, "Item", False, 7)
  Set dictProductNumbers = ProductNumberDict(wkstForecast, "Item", True, 3)

  Dim iRowStart As Long: iRowStart = 2
  Dim iFirstCol As Long: iFirstCol = 5
  With wkstForecast.Cells(iRowStart, iFirstCol).Resize(RowSize:=dictProductNumbers.Count)
  .Offset(ColumnOffset:=1).Value = WorksheetFunction.Transpose(dictProductNumbers.Keys)
  .Offset(ColumnOffset:=2).Value = WorksheetFunction.Transpose(dictProductNumbers.Items)
  End With

' ...

End Sub

特别注意用于将字典内容复制到工作表的非循环方法。

关于arrays - VBA动态数组错误地复制某些值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46453875/

相关文章:

javascript - Javascript 中的拆分函数不适用于对象中的字符串

excel - VBA 中变量动态范围的“运行时错误 13”。数据类型不匹配

c# - Wpf 产品在未安装 MS Office 的情况下导出到 Excel

excel - 调用 Form.Show vbmodeless 时,VBA 表单(自动)绑定(bind)/绑定(bind)到 ActiveWorksheet

c - 仅使用指针在动态结构中使用二维数组的 fscanf

php - 检查所有几个 PHP 数组键是否都存在

arrays - 当数组分配给 Sub 内的范围时,VBA 在结束语句或重置时崩溃

vba - SQL Server 2014 Express (VBA) 的连接字符串

vba - 仅当用户更改工作表时才调用 Sub,而不是 VBA 代码

c++ - 还有哪些其他语言可以通过指针操作来创建数组?