如何正确删除和更新数组元素?

时间:2018-01-11 01:44:10

标签: arrays excel vba excel-vba

我正在尝试根据特定情况发送群发电子邮件。

我创建了一个存储所有邮件地址的动态数组。理想的是,如果是checkInbox = true, 它将从数组中删除电子邮件,以便它不会发送给用户。

现在,它正在向所有用户发送。我尝试调试我的checkInbox,但它返回正确的 发件人电子邮件地址(即我)在条件范围内。

带有A = true

的数组的示例输出

enter image description here

我似乎无法找到我的错误。任何帮助表示赞赏。

感谢@ YowE3K提供MCVE示例

Sub test()
    Dim fpemail
    Dim cnt As Long
    cnt = 4
    ReDim fpemail(cnt)

    fpemail(1) = "A"
    fpemail(2) = "B"
    fpemail(3) = "A"
    fpemail(4) = "D"

    For i = 1 To cnt
        If fpemail(i) = "A" Then
            Call DeleteElementAt(i, fpemail)
        End If
    Next

    Debug.Print fpemail(1) ' displays "A"
    Debug.Print fpemail(2) ' displays "B"
End Sub

Public Sub DeleteElementAt(ByVal index As Integer, ByVal arr As Variant)
    Dim i As Integer

    For i = index + 1 To UBound(arr)
        arr(i - 1) = arr(i)
    Next

    ' Shrink the array by one, removing the last one
    ReDim Preserve arr(UBound(arr) - 1)
End Sub

2 个答案:

答案 0 :(得分:3)

您的问题的MCVE将如下所示:

Sub test()
    Dim fpemail
    Dim cnt As Long
    cnt = 4
    ReDim fpemail(cnt)

    fpemail(1) = "A"
    fpemail(2) = "B"
    fpemail(3) = "A"
    fpemail(4) = "D"

    For i = 1 To cnt
        If fpemail(i) = "A" Then
            Call DeleteElementAt(i, fpemail)
        End If
    Next

    Debug.Print fpemail(1) ' displays "A"
    Debug.Print fpemail(2) ' displays "B"
End Sub

Public Sub DeleteElementAt(ByVal index As Integer, ByVal arr As Variant)
    Dim i As Integer

    For i = index + 1 To UBound(arr)
        arr(i - 1) = arr(i)
    Next

    ' Shrink the array by one, removing the last one
    ReDim Preserve arr(UBound(arr) - 1)
End Sub

该代码存在几个问题:

  1. DeleteElementAt的程序声明表示arr已通过ByVal。因此,只将数组的副本传递给函数,从而避免任何影响调用例程的更改。您需要传递它ByRef

  2. 一旦从数组中删除了一个元素(例如第一个元素),那么第二个元素就变成了新的第一个元素,而过去的第三个元素就是新的第二个元素,等等。因此,您的For i = 1 to cnt循环将跳过已移至较早位置的位置。 (当然,在 第一个问题得到解决之后,这不会成为问题。)

  3. 代码的重构版本可能如下所示:

    Sub test()
        Dim fpemail
        Dim cnt As Long
        Dim i As Long
        cnt = 4
        ReDim fpemail(cnt)
    
        fpemail(1) = "A"
        fpemail(2) = "B"
        fpemail(3) = "A"
        fpemail(4) = "D"
    
        i = 1
        Do While i <= cnt
            If fpemail(i) = "A" Then
                Call DeleteElementAt(i, fpemail)
                cnt = cnt - 1 ' Reflects the fact that we now have one less position
                              ' Don't change i, because we still need to process
                              '     what has now been moved into that position of
                              '     the array
            Else
                i = i + 1     ' Increment i so that we look at the next position
                              '     of the array
            End If
        Loop
    
        Debug.Print fpemail(1) ' displays "B"
        Debug.Print fpemail(2) ' displays "D"
    End Sub
    
    Public Sub DeleteElementAt(ByVal index As Integer, ByRef arr As Variant)
        Dim i As Long
    
        For i = index + 1 To UBound(arr)
            arr(i - 1) = arr(i)
        Next
    
        ' Shrink the array by one, removing the last one
        ReDim Preserve arr(UBound(arr) - 1)
    End Sub
    

答案 1 :(得分:2)

或者您可以使用Collection代替您的阵列 易于填充,易于阅读和更新。

Dim fpemail As Collection, i As Long
Set fpemail = New Collection

With fpemail

    .Add "A"
    .Add "B"
    .Add "A"
    .Add "D"

    For i = .Count To 1 Step -1
        If .Item(i) = "A" Then
            .Remove (i)
        End If
    Next

    Debug.Print fpemail(1)
    Debug.Print fpemail(2)
End With