29

What is the fastest way to add a new item to an existing array?

Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4

(I already know that when working with dynamic list of items you should rather use a List, ArrayList or similar IEnumerables. But what to do if you're stuck to legacy code that uses arrays?)

What I've tried so far:

' A) converting to List, add item and convert back
Dim list As List(Of Integer)(arr)
list.Add(newItem)
arr = list.ToArray()
' --> duration for adding 100.000 items: 33270 msec

' B) redim array and add item
ReDim Preserve arr(arr.Length)
arr(arr.Length - 1) = newItem
' --> duration for adding 100.000 items: 9237 msec

' C) using Array.Resize
Array.Resize(arr, arr.Length + 1)
arr(arr.Length - 1) = newItem
' --> duration for adding 100.000 items: 1 msec
' --> duration for adding 100.000.000 items: 1168 msec

A) seems very slow since every time an item is added two conversions of the whole array are done. B) seems faster but still the array is copied once during the ReDim Preserve. C) seems to be the fastest at this point. Is there anything better?

jor
  • 2,058
  • 2
  • 26
  • 46
  • With the due respect, I think that you are comparing apples with mangoes: nobody wouldn't ever use your first alternative. One of the advantages of a list is how fast you can add new items to it (if you don't do the conversion to array, just add the item, you would see that it is much faster than any other alternative): if you are interested just in adding items quickly, use a list (don't rely on an array at all). Also list allow many more options to inspect/index its items than what arrays allow. BUT other than that, in pure performance (within loops, for example), they are much worse... – varocarbas Aug 07 '13 at 08:20
  • 4
    Summary: use arrays and lists in the best situations. Although VB.NET allows redimensioning, this is not what an array is expected to be passing through: arrays deliver the best performance under fixed-size conditions, just iterating over and over within its elements. On the other hand, Lists are meant for a less-iterative treatment: lower number of elements, regular changes in the dimensions, fancy queries to access the elements, etc. all these are functions which the arrays are not so good at. Thus, Arrays for performance under fixed-sized conditions; Lists for changing conditions. – varocarbas Aug 07 '13 at 08:24
  • 1
    PS: Lists are less memory-efficient too. – varocarbas Aug 07 '13 at 08:28
  • Thanks for your comments. The reason for building the tests like this is that I would like to have an `Extension` method for adding an item to an `Array`. That way the coding takes less lines :-) – jor Aug 07 '13 at 08:29
  • Well... if under your specific conditions it delivers the best result for you, do it; but, from a theoretical point of view, it does not make any sense: you are converting the definitory quick-item-adding features of lists into a really slow adding. On the other hand, one line of code less is something which cheers you up ;) – varocarbas Aug 07 '13 at 08:33
  • I really think you should just use list – user4951 Nov 08 '18 at 05:45

5 Answers5

43

Case C) is the fastest. Having this as an extension:

Public Module MyExtensions
    <Extension()> _
    Public Sub Add(Of T)(ByRef arr As T(), item As T)
        Array.Resize(arr, arr.Length + 1)
        arr(arr.Length - 1) = item
    End Sub
End Module

Usage:

Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4
arr.Add(newItem)

' --> duration for adding 100.000 items: 1 msec
' --> duration for adding 100.000.000 items: 1168 msec
jor
  • 2,058
  • 2
  • 26
  • 46
  • it should be Array.Resize(arr,arr.Length+1) I tried. – user4951 Jun 21 '14 at 15:28
  • For those who didn't know what next, just add new module file and put @jor code (with my little hacked, supporting 'nothing' array) below. +---- Edited, code jumbled. Go see my answer below. – Eric F. May 10 '15 at 11:54
  • 2
    I'm a long-time Python user playing around with VB for a proof-of-concept project. I stumbled on your solution when I found out VB doesn't support a '.add()' method for dynamically adding things to arrays, however when I put your code into a module, Visual Studio underlines `````` and reports "System.Runtime.CompilerServices.ExtensionAttribute is not accessible in this context because it is 'Friend'" I'm confused because the sub is public and the module is public. Any thoughts on what I'm noobing up? – Aaron C. de Bruyn Sep 19 '15 at 04:09
  • 2
    Add Imports System.Runtime.CompilerServices to use Extension – Samuel Surya Dec 04 '17 at 11:14
  • Keep in mind that the [`ExtensionAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.extensionattribute) is only available in .NET Framework 3.5+ – Sunny Patel Feb 11 '20 at 20:05
13
Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4
ReDim Preserve arr (3)
arr(3)=newItem

for more info Redim

Massimiliano Peluso
  • 26,379
  • 6
  • 61
  • 70
  • 5
    Technically speaking, you should have written: ReDim Preserve arr (3), otherwise you are over-dimensioning the array by 1. I personally don't care too much about this (I over-dimension arrays by one almost every time) but I guess that this would be a more proper answer. – varocarbas Aug 07 '13 at 08:09
  • the array has been initialized with 3 items and they want to add one more item so the size should be 4 isn't it? – Massimiliano Peluso Aug 07 '13 at 08:52
  • 1
    Yes, but ReDim Preserve arr (4) does not indicate a size of 4 but a highest index of 4, that is, a size of 5. As said, I shouldn't be giving lessons on this front as far as I am always doing what you do but, theoretically speaking, is not correct. – varocarbas Aug 07 '13 at 09:08
  • 1
    you are right. I have fixed my answer. This the bad side of knowing too many programming language:-) – Massimiliano Peluso Aug 07 '13 at 09:16
  • No problem. This is the typical mistake we all make. C# and VB have lots of parts in common and this kind of details might easily be overlooked. – varocarbas Aug 07 '13 at 09:30
  • I added "Imports System.Runtime.CompilerServices"before the module to get it to recognize Extensions. – Robert Cody Feb 09 '23 at 19:54
9

For those who didn't know what next, just add new module file and put @jor code (with my little hacked, supporting 'nothing' array) below.

Module ArrayExtension
    <Extension()> _
    Public Sub Add(Of T)(ByRef arr As T(), item As T)
        If arr IsNot Nothing Then
            Array.Resize(arr, arr.Length + 1)
            arr(arr.Length - 1) = item
        Else
            ReDim arr(0)
            arr(0) = item
        End If

    End Sub
End Module
Eric F.
  • 309
  • 4
  • 11
7

Not very clean but it works :)

Dim arr As Integer() = {1, 2, 3}
Dim newItem As Integer = 4

arr = arr.Concat({newItem}).ToArray
user6015865
  • 71
  • 1
  • 1
0

It depends on how often you insert or read. You can increase the array by more than one if needed.

numberOfItems = ??

' ...

If numberOfItems+1 >= arr.Length Then
    Array.Resize(arr, arr.Length + 10)
End If

arr(numberOfItems) = newItem
numberOfItems += 1

Also for A, you only need to get the array if needed.

Dim list As List(Of Integer)(arr) ' Do this only once, keep a reference to the list
                                  ' If you create a new List everything you add an item then this will never be fast

'...

list.Add(newItem)
arrayWasModified = True

' ...

Function GetArray()

    If arrayWasModified Then
        arr = list.ToArray()
    End If

    Return Arr
End Function

If you have the time, I suggest you convert it all to List and remove arrays.

* My code might not compile

the_lotus
  • 12,668
  • 3
  • 36
  • 53