Results 1 to 12 of 12

Thread: [RESOLVED] HELP delete a specific element of an Array

Threaded View

  1. #11
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: [RESOLVED] HELP delete a specific element of an Array

    Updated ArrayRemove
    Better performance (less API calls), better validation, can use arrays of any base (LBound can be something else than 0).
    Code:
    Option Explicit
    
    Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Arr() As Any) As Long
    Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Long)
    Private Declare Function SafeArrayRedim Lib "oleaut32" (ByVal saPtr As Long, saBound As Long) As Long
    
    Public Function ArrayRemove(ByVal NotNotArray As Long, ByVal Index As Long, Optional ByVal Items As Long = 1) As Boolean
        Dim A() As Long, AH(0 To 5) As Long, AP As Long
        Dim BSTRnull As Long, BSTRptr As Long, BSTRsize As Long
        Dim Arr As String, ArrI As Long, ArrL As Long, ArrT As String, Bounds(1) As Long
        Dim I As Long, L As Long, R As Long, S As Long
        ' IDE error fix (this will not be compiled)
        Debug.Assert App.hInstance
        ' start safe array hack
        AH(0) = 1: AH(1) = 4: AH(4) = &H3FFFFFFF
        AP = ArrPtr(A): PutMem4 AP, VarPtr(AH(0))
        ' now see if we got anything
        If (NotNotArray <> 0) And (Items > 0) Then
            ' get header information
            AH(3) = NotNotArray
            ' only allow one dimension
            If (A(0) And &HFFFF&) = 1 Then
                ' see if any data exists
                If A(3) <> 0 Then
                    ' lock status
                    If A(2) = 0 Then
                        ' zero base index
                        Index = Index - A(5)
                        ' cache number of items & item length in bytes
                        ArrI = A(4)
                        ArrL = A(1)
                        ' and finally we can validate index...
                        If (ArrI > Index) And (Index >= 0) Then
                            ' number of items to remove cannot exceed end of array
                            If (Index + Items) > ArrI Then
                                Items = ArrI - Index
                                If Items = 0 Then ArrI = 0
                            End If
                            ' end of array?
                            If ArrI > (Index + Items) Then
                                ' not an end of array, so we have to do some copying of data
                                L = ArrL * ArrI
                                ' items to be removed
                                R = Items * ArrL
                                ' calculate size that remains in the end
                                S = (ArrI - Index - Items) * ArrL
                                ' get BSTR pointer (= pointer to array data)
                                BSTRptr = A(3)
                                ' negative or positive pointer?
                                If BSTRptr >= 0 Then
                                    ' cache old data & replace with BSTR length
                                    AH(3) = BSTRptr - 4
                                    BSTRsize = A(0)
                                    A(0) = L
                                    ' cache old data & replace with BSTR terminator
                                    AH(3) = BSTRptr + L
                                    BSTRnull = A(0)
                                    A(0) = 0
                                Else
                                    ' cache old data & replace with BSTR length
                                    AH(3) = BSTRptr + 4
                                    BSTRsize = A(0)
                                    A(0) = L
                                    ' cache old data & replace with BSTR terminator
                                    AH(3) = BSTRptr - L
                                    BSTRnull = A(0)
                                    A(0) = 0
                                End If
                                ' point Arr to created BSTR
                                AH(3) = VarPtr(Arr): A(0) = BSTRptr
                                ' cache items to be removed
                                ArrT = MidB$(Arr, 1 + Index * ArrL, R)
                                ' now copy the end to the correct position
                                MidB$(Arr, 1 + Index * ArrL, S) = RightB$(Arr, S)
                                ' copy items to be removed to the end (this makes sure strings and objects are properly destroyed on array resize)
                                MidB$(Arr, L + 1 - R, R) = ArrT
                                ' memory clean up
                                ArrT = vbNullString
                                ' Arr no longer points to BSTR
                                A(0) = 0
                                ' negative or positive pointer?
                                If BSTRptr >= 0 Then
                                    ' restore old data
                                    AH(3) = BSTRptr - 4: A(0) = BSTRsize
                                    AH(3) = BSTRptr + L: A(0) = BSTRnull
                                Else
                                    ' restore old data
                                    AH(3) = BSTRptr + 4: A(0) = BSTRsize
                                    AH(3) = BSTRptr - L: A(0) = BSTRnull
                                End If
                                ' simply remove the items that are at the end of the array
                                AH(3) = NotNotArray
                                Bounds(0) = ArrI - Items
                                Bounds(1) = A(5)
                                ' true on success
                                ArrayRemove = (SafeArrayRedim(NotNotArray, Bounds(0)) = 0)
                            ElseIf ArrI > 0 Then
                                ' remove all items up to the index
                                Bounds(0) = Index
                                Bounds(1) = A(5)
                                ' true on success
                                ArrayRemove = (SafeArrayRedim(NotNotArray, Bounds(0)) = 0)
                            End If
                        End If
                    End If
                End If
            End If
        End If
        ' end safe array hack
        AH(3) = AP: A(0) = 0
    End Function
    I know, the code is long, but without proper validation it is far too dangerous to use it.

    Example
    Code:
    Option Explicit
    ' normally I don't like using this one here... but to get Array() to return an array that is one based...
    Option Base 1
    
    Private Sub Form_Load()
        Dim I As Long, Out As String, S() As Variant
        ' now create our one based array thanks to Option Base 1
        S = Array(11, 12, 13, 14, 15)
        ' then remove the second item (12)
        ArrayRemove Not Not S, 2
        ' build sample output...
        I = LBound(S)
        Out = I & " = " & S(I)
        For I = I + 1 To UBound(S)
            Out = Out & (vbNewLine & I & " = " & S(I))
        Next I
        ' show what we got
        MsgBox Out
    End Sub
    Last edited by Merri; Aug 15th, 2010 at 08:44 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width