How can I delete an item from an array in VB.NET? - vb.net

How can I delete an item from an array in VB.NET?

As Heinzi said, an array has a fixed size. In order to 'remove an item' or 'resize' it, you'll have to create a new array with the desired size and copy the items you need as appropriate.
Here's code to remove an item from an array:
<System.Runtime.CompilerServices.Extension()> _
Function RemoveAt(Of T)(ByVal arr As T(), ByVal index As Integer) As T()
Dim uBound = arr.GetUpperBound(0)
Dim lBound = arr.GetLowerBound(0)
Dim arrLen = uBound - lBound
If index < lBound OrElse index > uBound Then
Throw New ArgumentOutOfRangeException( _
String.Format("Index must be from {0} to {1}.", lBound, uBound))
Else
'create an array 1 element less than the input array
Dim outArr(arrLen - 1) As T
'copy the first part of the input array
Array.Copy(arr, 0, outArr, 0, index)
'then copy the second part of the input array
Array.Copy(arr, index + 1, outArr, index, uBound - index)
Return outArr
End If
End Function
You can use it as such:
Module Module1
Sub Main()
Dim arr = New String() {"abc", "mno", "xyz"}
arr.RemoveAt(1)
End Sub
End Module
The code above removes the second element ("mno") [which has an index of 1] from the array.
You need to be developing in .NET 3.5 or higher in order to use the extension method.
If you're using .NET 2.0 or 3.0, you can call the method as such
arr = RemoveAt(arr, 1)
I hope this is what you need.
Update
After running tests based on ToolMakerSteve's comment it appears the initial code does not modify the array you want to update because of the ByVal used in the function's declaration. However, writing code like arr = arr.RemoveAt(1) or arr = RemoveAt(arr, 1) does modify the array because it reassigns the modified array to the original.
Find below the updated method (subroutine) for removing an element from an array.
<System.Runtime.CompilerServices.Extension()> _
Public Sub RemoveAt(Of T)(ByRef arr As T(), ByVal index As Integer)
Dim uBound = arr.GetUpperBound(0)
Dim lBound = arr.GetLowerBound(0)
Dim arrLen = uBound - lBound
If index < lBound OrElse index > uBound Then
Throw New ArgumentOutOfRangeException( _
String.Format("Index must be from {0} to {1}.", lBound, uBound))
Else
'create an array 1 element less than the input array
Dim outArr(arrLen - 1) As T
'copy the first part of the input array
Array.Copy(arr, 0, outArr, 0, index)
'then copy the second part of the input array
Array.Copy(arr, index + 1, outArr, index, uBound - index)
arr = outArr
End If
End Sub
Usage of the method is similar to the original, except there is no return value this time so trying to assign an array from the return value will not work because nothing is returned.
Dim arr = New String() {"abc", "mno", "xyz"}
arr.RemoveAt(1) ' Output: {"abc", "mno"} (works on .NET 3.5 and higher)
RemoveAt(arr, 1) ' Output: {"abc", "mno"} (works on all versions of .NET fx)
arr = arr.RemoveAt(1) 'will not work; no return value
arr = RemoveAt(arr, 1) 'will not work; no return value
Note:
I use a temporary array for the process because it makes my intentions clear and that is exactly what VB.NET does behind the scenes when you do Redim Preserve. If you would like to modify the array in-place using Redim Preserve, see ToolmakerSteve's answer.
The RemoveAt methods written here are extension methods. In order for them to work, you will have to paste them in a Module. Extension methods will not work in VB.NET if they are placed in a Class.
Important If you will be modifying your array with lots of 'removes', it is highly recommended to use a different data structure such as List(Of T) as suggested by other answerers to this question.

You can't. I would suggest that you put the array elements into a List, at least then you can remove items. An array can be extended, for example using ReDim but you cannot remove array elements once they have been created. You would have to rebuild the array from scratch to do that.
If you can avoid it, don't use arrays here, use a List.

One line using LINQ:
Dim arr() As String = {"uno", "dos", "tres", "cuatro", "cinco"}
Dim indx As Integer = 2
arr = arr.Where(Function(item, index) index <> indx).ToArray 'arr = {"uno", "dos", "cuatro", "cinco"}
Remove first element:
arr = arr.Skip(1).ToArray
Remove last element:
arr = arr.Take(arr.length - 1).ToArray

That depends on what you mean by delete. An array has a fixed size, so deleting doesn't really make sense.
If you want to remove element i, one option would be to move all elements j > i one position to the left (a[j - 1] = a[j] for all j, or using Array.Copy) and then resize the array using ReDim Preserve.
So, unless you are forced to use an array by some external constraint, consider using a data structure more suitable for adding and removing items. List<T>, for example, also uses an array internally but takes care of all the resizing issues itself: For removing items, it uses the algorithm mentioned above (without the ReDim), which is why List<T>.RemoveAt is an O(n) operation.
There's a whole lot of different collection classes in the System.Collections.Generic namespace, optimized for different use cases. If removing items frequently is a requirement, there are lots of better options than an array (or even List<T>).

Yes, you can delete an element from an array. Here is an extension method that moves the elements as needed, then resizes the array one shorter:
' Remove element at index "index". Result is one element shorter.
' Similar to List.RemoveAt, but for arrays.
<System.Runtime.CompilerServices.Extension()> _
Public Sub RemoveAt(Of T)(ByRef a() As T, ByVal index As Integer)
' Move elements after "index" down 1 position.
Array.Copy(a, index + 1, a, index, UBound(a) - index)
' Shorten by 1 element.
ReDim Preserve a(UBound(a) - 1)
End Sub
Usage examples (assuming array starting with index 0):
Dim a() As String = {"Albert", "Betty", "Carlos", "David"}
a.RemoveAt(0) ' Remove first element => {"Betty", "Carlos", "David"}
a.RemoveAt(1) ' Remove second element => {"Betty", "David"}
a.RemoveAt(UBound(a)) ' Remove last element => {"Betty"}
Removing First or Last element is common, so here are convenience routines for doing so (I like code that expresses my intent more readably):
<System.Runtime.CompilerServices.Extension()> _
Public Sub DropFirstElement(Of T)(ByRef a() As T)
a.RemoveAt(0)
End Sub
<System.Runtime.CompilerServices.Extension()> _
Public Sub DropLastElement(Of T)(ByRef a() As T)
a.RemoveAt(UBound(a))
End Sub
Usage:
a.DropFirstElement()
a.DropLastElement()
And as Heinzi said, if you find yourself doing this, instead use List(Of T), if possible. List already has "RemoveAt" subroutine, and other routines useful for inserting/deleting elements.

My favorite way:
Imports System.Runtime.CompilerServices
<Extension()> _
Public Sub RemoveAll(Of T)(ByRef arr As T(), matching As Predicate(Of T))
If Not IsNothing(arr) Then
If arr.Count > 0 Then
Dim ls As List(Of T) = arr.ToList
ls.RemoveAll(matching)
arr = ls.ToArray
End If
End If
End Sub
Then in the code, whenever I need to remove something from an array I can do it by some property in some object in that array having a certain value, like:
arr.RemoveAll(Function(c) c.MasterContactID.Equals(customer.MasterContactID))
Or if I already know the exact object I want to remove, I can just do:
arr.RemoveAll(function(c) c.equals(customer))

The variable i represents the index of the element you want to delete:
System.Array.Clear(ArrayName, i, 1)

This may be a lazy man's solution, but can't you just delete the contents of the index you want removed by reassigning their values to 0 or "" and then ignore/skip these empty array elements instead of recreating and copying arrays on and off?

Public Sub ArrayDelAt(ByRef x As Array, ByVal stack As Integer)
For i = 0 To x.Length - 2
If i >= stack Then
x(i) = x(i + 1)
x(x.Length-1) = Nothing
End If
Next
End Sub
try this

Seems like this sounds more complicated than it is...
Dim myArray As String() = TextBox1.Lines
'First we count how many null elements there are...
Dim Counter As Integer = 0
For x = 0 To myArray.Count - 1
If Len(myArray(x)) < 1 Then
Counter += 1
End If
Next
'Then we dimension an array to be the size of the last array
'minus the amount of nulls found...
Dim tempArr(myArray.Count - Counter) As String
'Indexing starts at zero, so let's set the stage for that...
Counter = -1
For x = 0 To myArray.Count - 1
'Set the conditions for the new array as in
'It .contains("word"), has no value, length is less than 1, ect.
If Len(myArray(x)) > 1 Then
Counter += 1
'So if a value is present, we move that value over to
'the new array.
tempArr(Counter) = myArray(x)
End If
Next
Now you can assign tempArr back to the original or what ever you need done with it as in...
TextBox1.Lines = tempArr (You now have a textbox void of blank lines)

If the array is a string array you are able to then do the following:
AlphaSplit = "a\b\c".Split("\")
MaxIndex = AlphaSplit.GetUpperBound(0)
AlphaSplit = AlphaSplit.Where(Function(item, index) index <> MaxIndex).ToArray
AlphaJoin = String.Join("\", PublishRouteSplit)

How about this method:
Get a method which return an array, say tempArray
tempArray is supposed to have at least 1 less element to your array, say permArray
The method should take and integer param (this will be the index of the unwanted element) say ommitIndex and your permArray
In the method, copy all elements excluding the element as position ommitIndex from permArray to tempArray
The method returns tempArray so update permArray with the method.
Here's a snippet
Function updateArray(ommitIndex As Integer, array() As String) As Array
Dim tempArray(array.Length - 2) As String
Dim counter As Integer = 0
For i As Integer = 0 To (array.Length - 1)
If (i <> ommitIndex) Then
tempArray(counter) = array(i)
counter += 1
End If
Next
Return tempArray
End Function

Related

two-dimensional array to an array in visual basic

I've got a question about using two-dimensional array.
Public twolist(,) As String
For i As Integer = 0 To twolist.length()-1
If Func(twolist(i, )) Then 'this part is hard for me
'doing something
End If
Public Function Func(ByVal CancelInput() As String) As Boolean
What i want to do is Passing two-dimensional array to an array.
I want to read one row in two-dimensional array and pass to function(Func), which is using an array.
Hope You can understand my question... and Thank you!
As an alternative to the For Next Loop, you could use Linq (if you are confortable with it) to perform the same task.
This transforms each element of the source array to a String, groups them in an IEnumerable(Of String) and the result is converted to an unidimensional Array of Strings:
Dim twolist(N, N) As String
Dim CancelInput() As String = twolist.Cast(Of String).Select(Function(str) str).ToArray()
Dim result As Boolean = Func(CancelInput)
I have just used an arbitrary size for your array. You need nested For loops to iterate through a 2 dimensional array. The outer loop goes through the rows and the inner loop adds the value in each field to another array that you are passing to your Function. Each row is passed individually as a single dimension array.
Private Sub TwoDimensionalArray()
Dim twolist(,) As String
ReDim twolist(10, 5)
'First you will need to add data to your array
For x As Integer = 0 To 10
Dim arrayRow(5) As String
For y As Integer = 0 To 5
arrayRow(y) = twolist(x, y)
Next
If Func(arrayRow) Then 'this part is hard for me
'doing something
End If
Next
End Sub
Public Function Func(ByVal CancelInput() As String) As Boolean
Return True
End Function
Mary's answer is good, but assumes you know the length of each dimension.
I have changed it slightly to use the Array.GetLength function:
Private Sub TwoDimensionalArray()
Dim twolist(,) As String
ReDim twolist(10, 5)
'First you will need to add data to your array
For x As Integer = 0 To 10
'Fetch the length of this dimension:
Dim i As Integer = twolist.GetLength(x)
Dim arrayRow(i) As String
For y As Integer = 0 To i - 1
arrayRow(y) = twolist(x, y)
Next
If Func(arrayRow) Then
'do something
End If
Next
End Sub
Public Function Func(ByVal CancelInput() As String) As Boolean
Return True
End Function
Note:
In VB.Net, ReDim twoList(10,5) actually gives you an array of (11,6).
Array.GetLength(0) will return 6 (0,1,2,3,4,5).
In short, Dim specifies the maximum index in each dimension, Length & GetLength return the count of elements.

2D arrays throws index out of bound exception

I'm making a program and I keep getting the error Index was outside the bounds of the array and I can't figure out why. I tried all the different versions of setting up my 2D array.
Here is how I have it set up now
Dim dataArray(,) As Array = New Array(,) {{}}
Here is my loop for it
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = (DT.Rows(x).Item("Customer"))
dataArray(2, x) = (DT.Rows(x).Item("ShipBy"))
Next
You are declaring an array with a length of 0. That means that it will be unable to hold any data. All indexes will be out of range. Arrays do not automatically grow as items are added to them. As such, arrays should typically only be used in situations where the size of the array is fixed (unchanging). For instance:
Dim dataArray(2, 2) As Object ' Creates a 3x3 array of objects
If you want it to automatically grow as items are added, you would typically want to use a List(Of T) rather than an array. For instance:
Public Class MyItem
Public Property SO As Object
Public Property Customer As Object
Public Property ShipBy As Object
End Class
' ...
Dim dataList As New List(Of MyItem)()
' ...
Dim item As New MyItem()
item.SO = DT.Rows(x).Item("SO")
item.Customer = DT.Rows(x).Item("Customer")
item.ShipBy = DT.Rows(x).Item("ShipBy")
dataList.Add(item)
' ...
Label1.Text = dataList(1).SO
Or, if you insist on using an array to store each item, you can make a list of 1D arrays, like this:
Dim dataList As New List(Of Object())()
' ...
dataList.Add(
{
DT.Rows(x).Item("SO"),
DT.Rows(x).Item("Customer"),
DT.Rows(x).Item("ShipBy")
})
' ...
Label1.Text = dataList(1)(0)
As #Steven Doggart said (and beat me up to one minute with the answer) you are declaring an array, but you don't give the dimension length. You have two options:
specify the array dimension size at the declaration
or use Redim to set the (dimension) size of the array
In your case one solution could look like this:
Dim dataArray(,) As Array = New Array(3, DT.Rows.Count) {{}}
Or like this:
Dim dataArray(,) As Array = New Array(,) {{}}
Redim dataArray(3, DT.Rows.Count)
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = (DT.Rows(x).Item("Customer"))
dataArray(2, x) = (DT.Rows(x).Item("ShipBy"))
Next
Have a look at this MSDN Article - How to: Initialize an Array variable in VB.NET.
Dim dataArray(,) As Array = New Array(,) {{}}
This creates a two-dimensional array of Array, i.e. a two-dimensional array where each element is an Array. It's then initialized to an array containing a single, empty Array element. I expect this is not what you intended.
Since you never ReDim your array anywhere in the code to alter its dimensions, it remains a two-dimensional array whose first dimension is length 1, and whose second dimension is length zero.
When you try to run
dataArray(0, x) = DT.Rows(x).Item("SO")
The second dimension of the array has length zero, so it cannot hold a value. Thus you get an "index out of range" exception. If this did not happen, you would probably get another exception, because DT.Rows(x).Item("SO") probably is not an Array.
It would probably be easier to leave the data in the DataTable, and read from it whenever needed. Otherwise, I think your intent was to do something like:
Dim dataArray(0 To 3, -1) As Object 'Temporarily create a 2D Object array
'...load the DataTable
ReDim dataArray(0 to 3, 0 To DT.Rows.Count - 1) 'Redimension the array to the proper size.
'...rest of code

Add new value to integer array (Visual Basic 2010)

I've a dynamic integer array to which I wish to add new values. How can I do it?
Dim TeamIndex(), i As Integer
For i = 0 to 100
'TeamIndex(i).Add = <some value>
Next
Use ReDim with Preserve to increase the size of array with preserving old values.
ReDim in loop is advisable when you have no idea about the size and came to know for increasing the Array size one by one.
Dim TeamIndex(), i As Integer
For i = 0 to 100
ReDim Preserve TeamIndex(i)
TeamIndex(i) = <some value>
Next
If you to declare the size of array at later in code in shot then use
ReDim TeamIndex(100)
So the code will be :
Dim TeamIndex(), i As Integer
ReDim TeamIndex(100)
For i = 0 to 100
TeamIndex(i) = <some value>
Next
You can Use the ArrayList/List(Of T) to use Add/Remove the values more dynamically.
Sub Main()
' Create an ArrayList and add three strings to it.
Dim list As New ArrayList
list.Add("Dot")
list.Add("Net")
list.Add("Perls")
' Remove a string.
list.RemoveAt(1)
' Insert a string.
list.Insert(0, "Carrot")
' Remove a range.
list.RemoveRange(0, 2)
' Display.
Dim str As String
For Each str In list
Console.WriteLine(str)
Next
End Sub
List(Of T) MSDN
List(Of T) DotNetperls
There is nothing in Romil's answer that I consider to be wrong but I would go further. ReDim Preserve is a very useful command but it is important to realise that it is an expensive command and to use it wisely.
Consider:
Dim TeamIndex(), i As Integer
For i = 0 to 100
ReDim Preserve TeamIndex(i)
TeamIndex(i) = <some value>
Next
For every loop, except i=0, the Common Language Runtime (CLR) must:
find space for a new integer array that is one element bigger than the previous array
copy the values across from the previous array
initialise the new element
release the previous array for garbage collection.
ArrayList is fantastic if you need to add or remove elements from the middle of the array but you are paying for that functionality even if you do not need it. If, for example, you are reading values from a file and storing them sequentially but do not know in advance how many values there will be, ArrayList carries a heavy overhead you can avoid.
I always use ReDim like this:
Dim MyArray() As XXX
Dim InxMACrntMax As Integer
ReDim MyArray(1000)
InxMACrntMax=-1
Do While more data to add to MyArray
InxMACrntMax = InxMACrntMax + 1
If InxMACrntMax > UBound(MyArray) Then
ReDim Preserve MyArray(UBound(MyArray)+100)
End If
MyArray(InxMACrntMax) = NewValue
Loop
ReDim MyArray(InxMACrntMax) ' Discard excess elements
Above I have used 100 and 1000. The values I pick depend on my assessment of the likely requirement.

vb.net remove first element from array

One answer is to create a new array that is one element shorter. Are there any other simpler ways to do this?
You can use LINQ to produce your result in a very concise bit of code:
Dim a2 = a.Skip(1).ToArray();
You may have detractors say that this is slow and that you should use Array.Copy instead:
Dim a2(a.Length - 2) as Integer
Array.Copy(a, 1, a2, 0, a.Length - 1)
However, I tested the timings of both methods using an array of integers with 1,000,000 elements and found that LINQ took 29 milliseconds and the direct copy took 3 milliseconds. Unless you're doing some sort of crazy math with gazilions of elements then LINQ is fine and is far more readable.
Here is one way to remove the first element of an array in vb.net.
dim a(n)
...
for i = 1 to ubound(a)
a(i-1) = a(i)
next i
redim preserve a(ubound(a)-1)
You could make a function for this to remove an arbitrary element of an array (Have a parameter for the initial value of the for loop).
Combining #xpda's and #Enigmativity's answers, observe that Array.Copy can be safely used to copy back to the original array. Quote from msdn page for Array.Copy Method:
If sourceArray and destinationArray overlap, this method behaves as if the original values of sourceArray were preserved in a temporary location before destinationArray is overwritten.
Here is an (extension) subroutine that will remove element, at specified index, of an array of any type:
' Remove element at index "index". Result is one element shorter.
' Similar to List.RemoveAt, but for arrays.
<System.Runtime.CompilerServices.Extension()> _
Public Sub RemoveAt(Of T)(ByRef a() As T, ByVal index As Integer)
' Move elements after "index" down 1 position.
Array.Copy(a, index + 1, a, index, UBound(a) - index)
' Shorten by 1 element.
ReDim Preserve a(UBound(a) - 1)
End Sub
Usage examples (assuming array starting with index 0):
a.RemoveAt(0) ' Remove first element
a.RemoveAt(1) ' Remove second element.
a.RemoveAt(UBound(a)) ' Remove last element
Public xArray as variant
Function Array_DeleteFirstItem()
Dim i As Integer
For i = 0 To UBound(xArray) - 1
xArray (LBound(xArray) + i) = xArray(LBound(NotContainsArray) + i + 1)
Next
ReDim Preserve xArray(UBound(NotContainsArray) - 1)
For i = 0 To UBound(xArray)
Debug.Print xArray(i)
Next
End Function

Getting the index of the largest integer in an array

I have an array of integers and I need to know the index of the largest number (not the actual value, just the index of whichever is highest).
However, if one or more indexes "tie" for the highest value, I need to have all of the indexes that share that high value.
I assume this function would need to return an array (since it could be one or more indexes), but I am not totally sure how to go about getting the more efficient solution.
If this is going to be a common thing you could write your own Extension. You should add some additional sanity/null checking but this will get you started:
Module Extensions
<System.Runtime.CompilerServices.Extension()> Function FindAllIndexes(Of T)(ByVal array() As T, ByVal match As Predicate(Of T)) As Integer()
''//Our return object
Dim Ret As New List(Of Integer)
''//Current array index
Dim I As Integer = -1
''//Infinite loop, break out when we no more matches are found
Do While True
''//Loop for a match based on the last index found, add 1 so we dont keep returning the same value
I = System.Array.FindIndex(array, I + 1, match)
''//If we found something
If I >= 0 Then
''//Append to return object
Ret.Add(I)
Else
''//Otherwise break out of loop
Exit Do
End If
Loop
''//Return our array
Return Ret.ToArray()
End Function
End Module
Then to call it:
Dim ints As Integer() = New Integer() {1, 2, 8, 6, 8, 1, 4}
Dim S = ints.FindAllIndexes(Function(c) c = ints.Max())
''//S now holds 2 and 4
If you are using .NET 3.5, you can use the Max() Extension function to easily find the highest value, and use Where to locate the matching records in your source array.
IList has an IndexOf member, which helps. This code is completely untested, and probably has at least one off-by-one error.
Public Function GetPostionsOfMaxValue(ByVal input() As Integer) As Integer()
Dim ints = New List(Of Integer)(input)
Dim maxval = ints.Max
Dim indexes As New List(Of Integer)
Dim searchStart As Integer = 0
Do Until searchStart >= ints.Count
Dim index = ints.IndexOf(maxval, searchStart)
If index = -1 Then Exit Do
indexes.Add(index)
searchStart = index + 1
Loop
Return indexes.ToArray
End Function