VBA ArrayList类 还可以继续扩展
2014-04-03 20:59
302 查看
Option Explicit Private m_elements() As Variant Private m_size As Long Private m_capacity As Long Private m_dic As Dictionary Private Sub Class_Initialize() ReDim m_elements(9) m_size = 0 m_capacity = 10 Set m_dic = New Dictionary End Sub Public Property Get Capacity() As Long 'all capacity in the array, including unused space Capacity = UBound(m_elements) + 1 End Property Public Property Let Capacity(ByVal TotalCapacity As Long) ReDim Preserve m_elements(TotalCapacity - 1) m_capacity = TotalCapacity End Property Public Function Length() As Long 'includes only used elements in the array Length = m_size End Function Private Sub trimToSize() 'If capacity is large and length < 50% of capacity, 'trim total capacity to: (number of used elements * 1.5) If m_capacity > 99 Then If (m_size < (m_capacity / 2)) Then Dim newUBound As Long newUBound = Conversion.CLng(m_size * 1.5) If newUBound < 9 Then 'need at least 10 els newUBound = 9 End If ReDim Preserve m_elements(newUBound) m_capacity = newUBound + 1 End If End If End Sub Private Sub ensureCapacity(ByVal minCapacity As Long) If m_capacity < minCapacity Then Dim newUBound As Long newUBound = Conversion.CLng(m_capacity * 1.5) ReDim Preserve m_elements(newUBound) m_capacity = newUBound + 1 End If End Sub Public Function isEmpty() As Boolean isEmpty = (m_size = 0) End Function Public Sub Add(Item As Variant, Optional Key As String = "", Optional ByVal Before As Long = -1) 'Inserts the specified element at the specified position in this 'list. Shifts the element currently at that position (if any) and 'any subsequent elements to the right (adds one to their indices). Call ensureCapacity(m_size + 1) 'shift everything to the right of Before by 1 If (Before > -1) Then checkIndex (Before) Dim temp() As Variant ReDim temp(m_size) Call arrayCopy(m_elements(), Before, temp(), 0, m_size - Before) Call arrayCopy(temp(), 0, m_elements(), Before + 1, m_size - Before) If Not IsObject(Item) Then m_elements(Before) = Item Else Set m_elements(Before) = Item End If If Key <> "" Then If m_dic.Exists(Key) Then Call Err.Raise(Key, Description:="The Key can not allowed repeat") m_dic.Add Key, m_elements(Before) End If Else ' no "Before" param If Not IsObject(Item) Then m_elements(m_size) = Item Else Set m_elements(m_size) = Item End If If Key <> "" Then If m_dic.Exists(Key) Then Call Err.Raise(Key, Description:="The Key can not allowed repeat") m_dic.Add Key, Item End If End If m_size = m_size + 1 End Sub Sub removeAt(ByVal index As Long) checkIndex (index) If index < m_size - 1 Then Dim i As Integer For i = index To m_size - 1 If Not IsObject(m_elements(i + 1)) Then m_elements(i) = m_elements(i + 1) Else Set m_elements(i) = m_elements(i + 1) End If Next i m_elements(m_size - 1) = Empty ElseIf index = m_size - 1 Then m_elements(m_size - 1) = Empty End If m_size = m_size - 1 Call trimToSize End Sub Public Property Get ItemByKey(ByVal Key As String) As Variant If m_dic.Exists(Key) Then If IsObject(m_dic(Key)) Then Set ItemByKey = m_dic(Key) Exit Property Else ItemByKey = m_dic(Key) End If Else Call Err.Raise(Key, Description:="The Key can not find") End If End Property Public Property Get ItemByIndex(ByVal index As Long) As Variant If IsObject(m_elements(index - 1)) Then Set ItemByIndex = m_elements(index - 1) Exit Property Else ItemByIndex = m_elements(index - 1) End If End Property Public Property Let ItemByIndex(ByVal index As Long, ByVal value As Variant) checkIndex (index - 1) If IsObject(value) Then Set m_elements(index - 1) = value Else m_elements(index - 1) = value End If End Property Public Sub Remove(ByVal objElement As Variant) 'Remove the first occurrence of the given objElement Dim i As Long For i = 0 To m_size - 1 If (m_elements(i) = objElement) Then Call Me.removeAt(i) Exit For End If Next i End Sub Public Sub RemoveAll(ByVal objElement As Variant) 'Remove all occurrences of objElement Dim changes As Long changes = 0 Dim i As Long For i = 0 To m_size - 1 If (m_elements(i - changes) = objElement) Then Call Me.removeAt(i - changes) ' will decrement m_size changes = changes + 1 End If Next i Call trimToSize End Sub Public Sub RemoveRange(ByVal StartingIndex As Long, ByVal EndingIndex As Long) 'startindex= first element to remove index, endingindex=final element to remove 'TODO: what if startindex > endindex? checkIndex (StartingIndex) checkIndex (EndingIndex) Dim oldm_size As Long oldm_size = m_size 'get all the elements to the right of the range (if there are any elements to the right) If EndingIndex < m_size - 1 Then Dim temp() As Variant temp = Me.Items(EndingIndex + 1, m_size - 1) Call arrayCopy(temp, 0, m_elements, StartingIndex, UBound(temp) + 1) End If m_size = m_size - (EndingIndex - StartingIndex + 1) Dim i As Long For i = m_size To oldm_size - 1 m_elements(i) = Empty Next i End Sub Public Function Contains(ByRef Element As Variant) As Boolean Dim result As Boolean result = False Dim i As Long Dim e As Variant For Each e In m_elements If IsObject(Element) Then If e Is Element Then result = True Exit For End If Else If e = Element Then result = True Exit For End If End If i = i + 1 If i = m_size Then Exit For Next e Contains = result End Function Public Function indexOf(ByVal Element As Variant) As Long 'Searches for the specified Object and returns the zero-based index of 'the first occurrence within the entire ArrayList. 'Returns -1 if the Element was not found Dim result As Long result = -1 Dim index As Long index = 0 Dim e As Variant For Each e In m_elements If e = Element Then result = index Exit For End If index = index + 1 Next e indexOf = result End Function Public Function LastIndexOf(ByVal Element As Variant) As Long 'Searches for the specified Object and returns the 'zero-based index of the last occurrence within the entire ArrayList. 'Returns -1 if not found Dim result As Long result = -1 Dim i As Long For i = m_size - 1 To 0 Step -1 If m_elements(i) = Element Then result = i Exit For End If Next i LastIndexOf = result End Function Public Sub Clear() ReDim m_elements(9) m_capacity = 10 m_size = 0 End Sub Private Sub checkIndex(ByVal index As Long) If (index >= m_size) Or (index < 0) Then Call Err.Raise(index, Description:="The index specified is out of bounds") End If End Sub Public Sub Swap(ByVal Index1 As Long, ByVal Index2 As Long) Dim temp As Variant checkIndex (Index1) checkIndex (Index2) If Not IsObject(m_elements(Index2)) Then temp = m_elements(Index2) Else: Set temp = m_elements(Index2) End If If Not IsObject(m_elements(Index1)) Then m_elements(Index2) = m_elements(Index1) Else Set m_elements(Index2) = m_elements(Index1) End If If Not IsObject(temp) Then m_elements(Index1) = temp Else Set m_elements(Index1) = temp End If End Sub Public Sub Reverse() If m_size > 1 Then Dim hiIndex As Long hiIndex = m_size - 1 Dim loIndex As Long loIndex = 0 Do While (hiIndex > loIndex) Call Swap(loIndex, hiIndex) hiIndex = hiIndex - 1 loIndex = loIndex + 1 Loop End If End Sub Public Sub Shuffle() 'uses Fisher-Yates algo Dim i As Long Dim randomNbr As Long For i = m_size - 1 To 1 Step -1 Randomize 'random integer with 0 <= rndnbr <= i, uniformly distributed randomNbr = Int((i + 1) * Rnd) Call Swap(randomNbr, i) Next i End Sub Public Function GetDistinctValues() As ArrayList Dim distinctVals As New ArrayList Dim e As Variant For Each e In m_elements If Not distinctVals.Contains(e) Then distinctVals.Add e End If Next e Set GetDistinctValues = distinctVals End Function Public Function GetRange(ByVal StartingIndex As Long, ByVal TotalElementsToGet As Long) _ As ArrayList 'Returns a subset of the elements in this ArrayList. 'Index: The 0-based array index at which the range starts. 'Count: The number of elements in the range to get. Dim newAL As ArrayList Set newAL = New ArrayList If TotalElementsToGet > 0 Then Dim i As Long If TotalElementsToGet > 9 Then newAL.Capacity = TotalElementsToGet Else: newAL.Capacity = 10 End If For i = StartingIndex To (StartingIndex + TotalElementsToGet - 1) newAL.Add m_elements(i) Next i End If Set GetRange = newAL End Function Public Sub arrayCopy(array1() As Variant, ByVal startingIndex1 As Long, array2() As Variant, _ startingIndex2 As Long, ByVal TotalElements As Long) On Error Resume Next 'copies from arr1, starting at stin1, to arr2, starting at stin2, TotalElements. 'both arrays must be declared using syntax: dim array1(<number>) as <datatype> or redim array1(<number>) 'ensure arr2 has at least TE els If UBound(array2) < TotalElements - 1 Then ReDim Preserve array2(TotalElements - 1) End If Dim i As Long Dim j As Long j = startingIndex2 For i = startingIndex1 To startingIndex1 + TotalElements - 1 If Not IsObject(array1(i)) Then array2(j) = array1(i) Else: Set array2(j) = array1(i) End If j = j + 1 Next i End Sub Public Sub Sort() 'use quicksort algo If Me.ContainsObjects() Then MsgBox "This VBArrayList contains at least 1 object. Quicksort only works on alphanumeric values." Exit Sub Else Call QuickSort End If End Sub Private Sub QuickSort(Optional intLeft As Long = -2, _ Optional intRight As Long = -2) Dim i As Long Dim j As Long Dim varTestVal As Variant Dim intMid As Long If intLeft = -2 Then intLeft = 0 If intRight = -2 Then intRight = m_size - 1 If intLeft < intRight Then intMid = (intLeft + intRight) \ 2 varTestVal = m_elements(intMid) i = intLeft j = intRight Do Do While m_elements(i) < varTestVal i = i + 1 Loop Do While m_elements(j) > varTestVal j = j - 1 Loop If i <= j Then Call Me.Swap(i, j) i = i + 1 j = j - 1 End If Loop Until i > j If j <= intMid Then Call QuickSort(intLeft, j) Call QuickSort(i, intRight) Else Call QuickSort(i, intRight) Call QuickSort(intLeft, j) End If End If End Sub Public Function ContainsObjects() As Boolean Dim result As Boolean result = False Dim e As Variant For Each e In m_elements If IsObject(e) Then result = True Exit For End If Next e ContainsObjects = result End Function Public Function Items(Optional ByVal StartingIndex As Long = 0, Optional ByVal EndingIndex As Long = -1) As Variant() If EndingIndex = -1 Then EndingIndex = m_size - 1 Dim els() As Variant ReDim els(EndingIndex - StartingIndex) Dim i As Long Dim j As Long j = 0 If StartingIndex <= EndingIndex Then For i = StartingIndex To EndingIndex If Not IsObject(m_elements(i)) Then els(j) = m_elements(i) Else Set els(j) = m_elements(i) End If j = j + 1 Next i Else For i = StartingIndex To EndingIndex Step -1 If Not IsObject(m_elements(i)) Then els(j) = m_elements(i) Else Set els(j) = m_elements(i) End If j = j + 1 Next i End If Items = els End Function Public Function ToCollection() As Collection Dim coll As New Collection Dim i As Long For i = 0 To m_size - 1 coll.Add m_elements(i) Next i Set ToCollection = coll End Function Public Function ToArray() As Variant() ToArray = m_elements End Function Public Sub IntakeArray(yourArray() As Variant) 'array must be a variant array m_elements = yourArray m_capacity = Me.Capacity m_size = Me.Length End Sub Public Sub IntakeCollection(ByVal yourCollection As Collection) 'completely replaces anything in m_elements with the elements of a collection 'do not use parentheses around the argument ReDim m_elements(yourCollection.Count - 1) Dim i As Long For i = 0 To UBound(m_elements) If IsObject(yourCollection.Item(i + 1)) Then Set m_elements(i) = yourCollection.Item(i + 1) Else: m_elements(i) = yourCollection.Item(i + 1) End If Next i m_capacity = Me.Capacity m_size = Me.Length End Sub
相关文章推荐
- 一个比较有用的XML文件操作类 C#代码 可以继续扩展
- 无法创建网站“http://localhost:8082/WebSite”。若要在本地 IIS Web 服务器上访问网站,必须以管理员帐户运行 Visual Studio 以便能够访问 IIS 元数据库。也可以安装 FrontPage 服务器扩展(FPSE
- 夕阳桥断 Linux(centos6.5)下安装jenkins Jenkins 的前身是 Hudson 是一个可扩展的持续集成引擎。 通俗的来讲,jenkins就是一个可以实现自动化部署的一个插
- 一个可以从excel中读取数据并生成xml的vba程序
- system\classes\Kohana.php 空的核心扩展文件也可以把它复制到application\classes下面写自己的扩展
- 安装SQL2008时显示必须重启计算机才可以继续安装的错误解决
- 适合于Unix与Win32下的字符串处理类,可以以此为基类进行扩展
- 这些年收藏的技术大牛博客分享(后续还会继续更新)大家可以在评论中分享自己关注的
- 28岁,很困惑自己是否可以继续从事码农的职业
- 万圣节到了,来讲鬼故事吧!(大家可以在回复中继续讲)
- coreData旧版本增加字段,新版本是否可以继续使用旧版本内容的测试(MagicalRecord的使用)
- 练习3-3 编写函数 expand(s1, s2),将字符串s1 中类似于a-z 一类的速记符号在字符串s2中扩展为等价的完整列表abc…xyz。该函数可以处理大小写字母和数字。
- 扩展欧几里德 求最小整数解 a,b,c可以为负数
- Struts的扩展:添加可以传参数的ActionForward(一)
- 中国被爱可以在线2006继续专注于WAP领域
- 指数计算 m^n (可以扩展到矩阵的n次方)
- Win7,Win8的扩展卷功能只能在分区的尾部继续向后延伸
- ExtJs--14--Ext.typeOf() 与 javascript中的typeof很相似,只是在类型上进行了一点简单的扩展,其实可以直接看源代码就可以看得懂的
- System.Collections.ArrayList类是一个特殊的数组。通过添加和删除元素,就可以动态改变数组的长度。
- A7139 无线通信驱动(STM32) 增加FIFO扩展模式,可以发送超大数据包