Creating Useful Array Functions

Visual Basic Scripting Edition doesn’t provide very good support for working with arrays. It has a very limited number of array functions, especially when compared to similar languages like JavaScript. In this article, I’m going to show you some custom functions you can add to your scripts that will give you the flexibility you might find in other languages.

Pop and Push

Many languages feature the Pop function, which is used to remove the last element from an array.  The function returns the contents of the removed element.

Function Pop(ByRef arrArray)

   ‘ Remove and return the last element of an array.

   If UBound(arrArray) = 0 Then Pop = vbNull : Exit Function

   Pop = arrArray(UBound(arrArray))

   ReDim Preserve arrArray(UBound(arrArray) – 1)

End Function

Here you can see the Pop function.  It requires a single parameter that is the array on which to act.  Notice that I’m passing the array by reference (using the ByRef keyword).  This forces the function to act on the original array and not a duplicated array.

The function begins by finding the upper boundary of the array.  This provides the number of elements in the array.  If this number is 0, then the array has only a single element and the function will exit without doing anything.  In this instance, the function returns a Null value.

Suppose that the array does contain more than one element; the last element is read, and then the array is resized to be one element smaller than it started.  Using the Preserve keyword, we ensure that the remaining array elements remain unchanged.

The Push function is the opposite of Pop.  Rather than removing an element, it adds an element to the end of an array and returns a value indicating the new size of the array.

Function Push(ByRef arrArray, varElement)

   ‘ Add an element to the end of an array. Return new length.

   ReDim arrArray(UBound(arrArray) + 1)

   arrArray(UBound(arrArray)) = varElement

   Push = UBound(arrArray)

End Function

You can see here that the structure of the Push function is very similar to the one you just saw in Pop.  Here though, we begin by adding an element to the end of the array and assigning it the value from a passed parameter.  We then grab the new length of the array with the Ubound function and return that value.

{mospagebreak title=Using Shift and Unshift}

Where the last two functions we looked at worked with the last element in an array, the next two functions work with the first element instead.  The Shift function, similar to Pop, will remove the first element in an array.

Function Shift(ByRef arrArray)

   ‘Remove and return the first element of an array

   If UBound(arrArray) = 0 Then Shift = vbNull : Exit Function

   Shift = arrArray(0)

   For i = 0 To UBound(arrArray) – 1

       arrArray(i) = arrArray(i + 1)

   Next

   ReDim Preserve arrArray(UBound(arrArray) – 1)

End Function

The code for the Shift function should looked vaguely familiar.  It’s very similar to Pop, except that we have to manipulate the existing elements a bit.  Again, we do a simple check to determine whether or not the array contains more than one element.  If it does, we immediately return the value of the first element.

Next, we create a For loop that moves through the elements in the array, assigning each of them with the value of the element that follows.  This effectively moves each element back by one index.  The duplicate is then removed from the end of the array.  The resulting array is the same as if the first element had simply been removed.

The Unshift function is the converse of the Shift function.  This one adds an element to the beginning of an array and returns the length of the new array.

Function Unshift(ByRef arrArray, varElement)

   ‘ Add an element to the beginning of an array. Return new length.

   ReDim arrArray(UBound(arrArray) + 1)

   For i = UBound(arrArray) – 1 To 1 Step -1

       arrArray(i – 1) = arrArray(i)

   Next

   arrArray(0) = varElement

   Unshift = UBound(arrArray)

End Function

Unlike Shift, the Unshift function begins by resizing the array first.  In this way, an empty element is added to the end of the array.  Next, a loop is created that moves backward through the array, moving elements up by one index.  It’s very important that we process the array backwards in this case, otherwise we would simply be overwriting every element with the exact same value.  Notice the use of Step -1 in my For loop.

Once the array elements are shifted up by one index, the provided value is assigned to the array and the new length of the array is returned.  Notice again that the array is passed into the function by reference.

{mospagebreak title=Using Slice and Splice} 

The Slice and Splice functions are similar to those you’ve already seen, but they are slightly more complicated.  We’ll begin with the Slice function; it’s used to return a specified number of elements from an array.  These elements must be in order, and they are not removed.

Function Slice(ByRef arrArray, intStart, intEnd)

   ‘ Remove and return specified number of elements in an array.

   If intEnd = vbNull Then intEnd = UBound(arrArray)

   If intStart < 0 Then intStart = UBound(arrArray) – intStart

The function requires three parameters.  (The third is optional, but VBScript does not allow us to specify optional parameters.  Instead, a Null value may be passed rather than a specified value).  The first parameter is the array, followed by the starting index and the ending index.  If the ending index is not specified, the function will remove all elements to the end of the array.

   arrTemp = Array()

   intCount = 0

   For i = intStart To intEnd

       ReDim Preserve arrTemp(intCount)

       arrTemp(intCount) = arrArray(i)

       intCount = intCount + 1

   Next

The process looks identical to both Pop and Shift, except that we loop through the array indices based on the provided starting and ending values.  Each value is assigned to a new temporary array in order.

   For i = intStart To intEnd – UBound(arrTemp) – 1

       arrArray(i) = arrArray(i + UBound(arrTemp))

   Next

   ReDim Preserve arrArray(UBound(arrArray) – UBound(arrTemp))

The remaining values in the array (if any) are then copied to replace the ones that were removed.  The array is then resized to remove the duplicates.

   Select Case UBound(arrTemp)

       Case 0

          Slice = arrTemp(0)

       Case Else

          Slice = arrTemp

   End Select

End Function

Finally, we use a Select Case structure to determine what to return.  If the temporary array contains a single value, we return that value alone; if it contains multiple values, we return them as an array.

The Splice function is a bit complicated, but it should seem pretty easy to you now that you’ve seen how Slice works.

Function Splice(ByRef arrArray, intIndex, varElement)

   ‘ Add element(s) to an array at a specified index.

   If intIndex < 0 Or intIndex > UBound(arrArray) Then Exit Function

   If IsArray(varElement) Then

       ReDim Preserve arrArray(UBound(arrArray) + UBound(varElement) + 1)

       For i = intIndex To UBound(varElement) – 1

          arrArray(i) = arrArray(UBound(varElement) + 1)

       Next

       For i = 0 To UBound(varElement)

          arrArray(intIndex + i) = varElement(i)

       Next

   Else

       ReDim Preserve arrArray(UBound(arrArray) + 1)

       For i = intIndex To UBound(arrArray) – 1

          arrArray(i) = arrArray(i + 1)

       Next

       arrArray(intIndex) = varElement

   End If

   Splice = Ubound(arrArray)

End Function

With Splice, we’re adding elements.  We first determine whether a single element is to be added or an array of elements.  Then the array is resized to fit the additional elements, and the existing elements are moved to their new positions.  Once the provided values are assigned to the array, the array’s new length is returned.

{mospagebreak title=Using Concat and Compact}

The Concat function is used to append one array to another.  The result is a new array containing the elements from both original arrays.

Function Concat(arrArray1, arrArray2)

   ‘ Appends one array to another.  Returns new array.

   arrTemp = Array()

   ReDim arrTemp(UBound(arrArray1) + UBound(arrArray2) + 2)

   intCount = 0

   For i = 0 To UBound(arrArray1)

      ReDim Preserve arrTemp(intCount)

       arrTemp(intCount) = arrArray1(i)

       intCount = intCount + 1

   Next

   For i = 0 To UBound(arrArray2)

       ReDim Preserve arrTemp(intCount)

       arrTemp(intCount) = arrArray2(i)

       intCount = intCount + 1

   Next

   Concat = arrTemp

End Function

The Concat function begins by creating a new temporary array.  Its length is the sum of the lengths of the arrays to be combined.  Two For loops are each used in turn to add the values from the existing arrays. The function then returns the new array.

The Compact function is used to remove empty, Null, and duplicate entries from an array.  It returns the size of the array after the operations have been completed.

Function Compact(ByRef arrArray)

   ‘ Removes empty/null and duplicate entries in an array. Return new length.

   With CreateObject("Scripting.Dictionary")

       .RemoveAll

       .CompareMode = 0

       For Each varItem In arrArray

          If Len(varItem) > 0 Then

             If Not .Exists(varItem) Then .Add varItem, varItem

          End If

       Next

       arrKeys = .Keys

   End With

The Compact function creates a new Dictionary object.  Each element from the provided array is then added to the Dictionary object if its length is greater than 0, indicating that it is neither Null nor Empty.  The Dictionary object’s Exists method is used to determine whether a value exists before it is added.  This prevents any duplicates.

   ReDim arrArray(UBound(arrKeys))

   For i = 0 To UBound(arrKeys)

       arrArray(i) = arrKeys(i)

   Next

   Compact = UBound(arrArray)

End Function

All of the elements in the array are then cleared and the contents of the Dictionary object are added back to the array.  The resulting array is returned.

{mospagebreak title=Using Sort and Reverse}

Finally, VBScript lacks any good way to sort the contents of an array.  The last two functions I’d like to present today are geared to that end.  The first is a simple Sort function that will allow you to sort an array in either ascending or descending order.  The second is a Reverse function that will allow you to reverse the order of an array’s elements.

Function SortB(ByRef arrArray, intAsc)

   ‘ Sort elements in an array

   ‘ Const ASCENDING = 0

   ‘ Const DESCENDING = 1

   Set ArrayList = CreateObject("System.Collections.ArrayList")

   For Each varItem In arrArray

       ArrayList.Add varItem

   Next

   ArrayList.Sort()

   If Not CBool(intAsc) Then ArrayList.Reverse()

  

   intCount = 0

   For Each varListItem In ArrayList

       arrArray(intCount) = varListItem

       intCount = intCount + 1

   Next

End Function

The simplest approach I’ve found to sorting arrays in VBScript uses a .NET Interop that wasn’t actually intended for use in scripting.  Luckily for us, it does provide a scriptable interface that we can use.

This function creates a .Net ArrayList object and adds each element in an array to it.  It then uses a Sort or Reverse method on the ArrayList, depending on whether the provided parameters indicate an ascending or descending sort.  The newly sorted ArrayList elements are then written back the original array.

The Reverse function is used to reverse the order of elements in an array.

Function Reverse(ByRef arrArray)

   ‘ Reverse the order of elements in an array

   For i = 0 To Int(UBound(arrArray) / 2)

       varTemp = arrArray(i)

       arrArray(i) = arrArray(UBound(arrArray) – i)

       arrArray(UBound(arrArray) – i) = varTemp

   Next

End Function

The For Loop steps through each element up to the middle element in an array, switching the elements from the beginning and end.  The first element is switched with the first element from the end, the second element is switched with the second element from the end, and so on.  Notice here that we’re dividing the upper boundary by two.  We don’t want to continue processing the elements passed the middle of the array or we’ll simply be undoing the work we’ve already done.

That wraps up most of the array functions I have in my arsenal.  I have a few left, but we’ll save those for another article.  I hope that you find these functions useful.  Consider packaging them in a class for use in later scripts.  Learning to use arrays properly—and now more effectively—will greatly increase the flexibility and power of your scripts.  Until next time, keep coding!

[gp-comments width="770" linklove="off" ]