J
John Brock
A little while ago I posted two versions of a Perl inspired array
splice routine. But because the version for VB.NET was derived
from the one for VBA it was overly complicated, so I'm posting a
simplified and improved VB.NET version.
I'm posting this routine so that it can be found by people facing
the same problem I was faced with: the fact that VB.NET has no
convenient way to insert or delete elements from arrays. After my
original post various people pointed out this problem can be solved
by using the List(T) generic class instead of arrays, and if you
are starting from scratch this is no doubt the way to go. But if
you are in a position like mine, where performance is not an issue
(my app is heavily IO bound), and where converting from arrays to
List(T) would involve reviewing and possibly updating hundreds of
functions and tens of thousands of lines of code (much of which
hasn't been touched in years), than relying on a simple little
function like this one might make more sense.
'A splice function inspired by the one in Perl, but not identical. Remove "length"
'elements from "arrayIn" starting at "offset", insert "list", and return the result.
'(A negative "offset" means append to end; a negative "length" inserts null elements).
Public Function ArraySplice(Of T)( _
ByVal arrayIn As T(), _
ByVal offset As Integer, _
ByVal length As Integer, _
ByVal ParamArray list As T()) As T()
If arrayIn Is Nothing Then Array.Resize(arrayIn, 0) 'Convert Nothing to a zero-length array.
If list Is Nothing Then Array.Resize(list, 0) 'Convert Nothing to a zero-length array.
If offset < 0 Then offset = arrayIn.Length 'Append to end.
Dim effLen As Integer = arrayIn.Length 'The effective length of the input array.
Dim lCopy As Integer = offset 'Number of elements to copy from left of input array.
'When the offset falls outside the input array the roles of effLen and lCopy are reversed.
If offset >= arrayIn.Length Then
effLen = offset 'The input array is effectively extended all the way to the offset.
lCopy = arrayIn.Length 'Can't copy more than we were given.
End If
If length > effLen - offset Then length = effLen - offset 'Can't remove what you haven't got.
Dim rCopy As Integer = effLen - offset 'Number of elements to copy from right of input array.
If length > 0 Then rCopy = rCopy - length 'Don't copy elements being removed.
Dim arrayOut(effLen + list.Length - length - 1) As T 'Allocate a properly sized output array...
'...and copy the appropriate ranges into it.
If lCopy > 0 Then Array.Copy(arrayIn, 0, arrayOut, 0, lCopy)
If list.Length > 0 Then Array.Copy(list, 0, arrayOut, offset, list.Length)
If rCopy > 0 Then Array.Copy(arrayIn, arrayIn.Length - rCopy, arrayOut, arrayOut.Length - rCopy, rCopy)
Return arrayOut
End Function
splice routine. But because the version for VB.NET was derived
from the one for VBA it was overly complicated, so I'm posting a
simplified and improved VB.NET version.
I'm posting this routine so that it can be found by people facing
the same problem I was faced with: the fact that VB.NET has no
convenient way to insert or delete elements from arrays. After my
original post various people pointed out this problem can be solved
by using the List(T) generic class instead of arrays, and if you
are starting from scratch this is no doubt the way to go. But if
you are in a position like mine, where performance is not an issue
(my app is heavily IO bound), and where converting from arrays to
List(T) would involve reviewing and possibly updating hundreds of
functions and tens of thousands of lines of code (much of which
hasn't been touched in years), than relying on a simple little
function like this one might make more sense.
'A splice function inspired by the one in Perl, but not identical. Remove "length"
'elements from "arrayIn" starting at "offset", insert "list", and return the result.
'(A negative "offset" means append to end; a negative "length" inserts null elements).
Public Function ArraySplice(Of T)( _
ByVal arrayIn As T(), _
ByVal offset As Integer, _
ByVal length As Integer, _
ByVal ParamArray list As T()) As T()
If arrayIn Is Nothing Then Array.Resize(arrayIn, 0) 'Convert Nothing to a zero-length array.
If list Is Nothing Then Array.Resize(list, 0) 'Convert Nothing to a zero-length array.
If offset < 0 Then offset = arrayIn.Length 'Append to end.
Dim effLen As Integer = arrayIn.Length 'The effective length of the input array.
Dim lCopy As Integer = offset 'Number of elements to copy from left of input array.
'When the offset falls outside the input array the roles of effLen and lCopy are reversed.
If offset >= arrayIn.Length Then
effLen = offset 'The input array is effectively extended all the way to the offset.
lCopy = arrayIn.Length 'Can't copy more than we were given.
End If
If length > effLen - offset Then length = effLen - offset 'Can't remove what you haven't got.
Dim rCopy As Integer = effLen - offset 'Number of elements to copy from right of input array.
If length > 0 Then rCopy = rCopy - length 'Don't copy elements being removed.
Dim arrayOut(effLen + list.Length - length - 1) As T 'Allocate a properly sized output array...
'...and copy the appropriate ranges into it.
If lCopy > 0 Then Array.Copy(arrayIn, 0, arrayOut, 0, lCopy)
If list.Length > 0 Then Array.Copy(list, 0, arrayOut, offset, list.Length)
If rCopy > 0 Then Array.Copy(arrayIn, arrayIn.Length - rCopy, arrayOut, arrayOut.Length - rCopy, rCopy)
Return arrayOut
End Function