Quantcast
Channel: VBA Python-like List Class - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 4

VBA Python-like List Class

$
0
0

VBA's Collection class is lacking so I created a basic List class using Python's as a template. This could make future derived classes easier to implement.

The biggest features are better setting and accessing of values. But one neat-o feature is Python-style indexing.

Dim myList As ListmyList.Extend(Array(1,2,3,4,5,6))Debug.Print myList(-2) ' 5Debug.print myList.Slice(-1, 1).ToString '"[6,5,4,3,2,1]"

Note: I kept VBA's 1 offset for collections. This means that there is a hole at index 0 and will always return subscript out of range. I don't like it but this way List's will play nice with VBA's collection objects.

Private members

Option ExplicitPrivate collec As Collection ' Sole datamember

TransformIndex: Enforces Zero Offset and Cylcing.

Private Sub TransformIndex(ByRef x As Variant)    If x < 0 Then x = x + collec.Count + 1End Sub

Replace is private; use Item and Slice to actually replace elements

Private Sub Replace(ByVal index As Long, ByVal element As Variant)    collec.Remove index    If index = collec.Count + 1 Then        collec.Add element    Else        collec.Add element, before:=index    End IfEnd Sub

Some boring stuff

Private Sub Class_Initialize()    Set collec = New CollectionEnd SubPrivate Sub Class_Terminate()    Set collec = NothingEnd SubPublic Property Get NewEnum() As IUnknownAttribute NewEnum.VB_UserMemId = -4    Set NewEnum = collec.[_NewEnum]End Property

Public Methods

The general pattern for these is and implementation of one action for a single element and another for a sequence of elements. e.g.Item and then Slice or Append and Extend. The only exception is removal that only implements single elements.

Accessers and Replacement

Item and Slice provide general access to members and allows replacement as they are not read only.

Public Property Let Item(ByVal index As Long, ByVal element As Variant)Attribute Item.VB_UserMemId = 0    TransformIndex index    Replace index, elementEnd PropertyPublic Property Set Item(ByVal index As Long, ByVal element As Variant)Attribute Item.VB_UserMemId = 0    TransformIndex index    Replace index, elementEnd Property

seq is an auxiliary module for general sequence functions. For purposes of this review assume functions from it does exactly what it should do. seq.Assign(x,y) assign's or sets x to y.

Public Property Get Item(ByVal index As Long) As VariantAttribute Item.VB_UserMemId = 0    TransformIndex index    seq.Assign Item, collec.Item(index)End Property

Slice: Allows for accessing sub sequences from a to b. Regardless of the order. You can specify a step s to skip elements but note that s must be a natural number. If you want to get a reversed sequence make b less than a not a negative s.

Also Slice is read-write, so it allows replacement of sub-sequences.

Public Property Get Slice(ByVal a As Long, ByVal b As Long, Optional ByVal s As Long = 1) As List    TransformIndex a    TransformIndex b    Set Slice = New List    If s < 1 Then Err.Raise "List.Slice", "Step "& s & " is not a natural number."    s = IIF(a < b, s, -s)    Dim i As Long    For i = a To b Step s        Slice.Append collec.Item(i)    Next iEnd PropertyPublic Property Let Slice(ByVal a As Long, ByVal b As Long, Optional ByVal s As Long = 1, ByVal sequence As Variant)    TransformIndex a    TransformIndex b    If s < 1 Then Err.Raise "List.Slice", "Step "& s & " is not a natural number."    s = IIF(a < b, s, -s)    If Abs(a - b) + 1 <> seq.Length(sequence) Then        Err.Raise 9, "List.Slice", "Subscript out of Range."    End If    Dim i As Long: i = a    Dim element As Variant    For Each element In sequence        Replace i, element        i = i + s    Next element    Debug.Assert (i - s = b)End Property

Removal Methods

Public Sub Remove(ByVal index As Long)    TransformIndex index    collec.Remove indexEnd Sub''' List.Clear(x, y) \equiv List.Clear(y, x)Public Sub Clear(ByVal a As Long, ByVal b As Long)    TransformIndex a    TransformIndex b' Order of removal is irrelevant    If a > b Then seq.Swap a, b    Dim i As Long    For i = 0 To b - a        collec.Remove a    Next iEnd Sub

I have been trying to work out a RemoveRange function. I will update with them later. Added a Clear function. Note List.Clear(x, y) \$ \equiv \$ List.Clear(y, x).

Appending Methods

Public Sub Append(ByVal element As Variant)    collec.Add elementEnd SubPublic Sub Extend(ByVal sequence As Variant)    Dim element As Variant    For Each element In sequence        collec.Add element    Next elementEnd Sub

Insertion Methods

Public Sub Emplace(ByVal index As Long, ByVal element As Variant)    TransformIndex index    collec.Add element, before:=indexEnd SubPublic Sub Insert(ByVal index As Long, ByVal sequence As Variant)    TransformIndex index    seq.Reverse sequence    Dim element As Variant    For Each element In sequence        collec.Add element, before:=index    Next elementEnd Sub

Auxiliary Methods

Public Property Get Count() As Long    Count = collec.CountEnd PropertyPublic Function Exists(ByVal sought As Variant) As Boolean    Exists = True    Dim element As Variant    For Each element In collec        If element = sought Then Exit Function    Next element    Exists = FalseEnd FunctionPublic Property Get ToString() As String    ToString = "["& Join(seq.ToArray(collec), ", ") & "]"End Property

Viewing all articles
Browse latest Browse all 4

Latest Images

Trending Articles





Latest Images