Results 1 to 11 of 11

Thread: Array or List

  1. #1

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,753

    Array or List

    So for those of you who do not know, I created a Visual Basic FAQ thread on which collection should I use. However, I ran across a situation that I need y'all's help on figuring out which collection I should use.

    My situation is this: I have a bunch of sensors that I monitor, I click a Button and it scans for all of the sensors. When the scan is finished it returns a fixed collection of sensors, which I store into an array. However, with this being a possibility of being rescanned, I feel like I should use a List instead since the number of items can change. So my question to y'all, is which should I use:

    Fixed collection solution:
    Code:
    'Declared at the Form level: Dim sensors() As Sensor
    
    'Redeclare the variable to match the number of returned sensors
    ReDim sensors(monitor.Sensors.Count - 1)
    
    'Create a counter to keep track of where to insert the sensor in the array
    Dim counter As Integer = 0
    
    'Iterate through each sensor
    For Each sensor As HostSensor In monitor.Hosts
        'Add the sensor to the array
        sensors(counter) = New Sensor() With {.IP = sensor.IPAddressString, .Name = sensor.Name}
    
        'Increment the counter
        counter += 1
    Next
    Dynamic length collection:
    Code:
    'Declared at the Form level: Dim sensors As New List(Of Sensor)
    
    'Clear the collection
    sensors.Clear()
    
    'Iterate through each sensor
    For Each sensor As HostSensor In monitor.Hosts
        'Add the sensor to the array
        sensors.Add(New Sensor() With {.IP = sensor.IPAddressString, .Name = sensor.Name})
    Next
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: Array or List

    The only drawback to using the List that I am aware of is if it keeps resizing. The list will resize more efficiently if it has to resize. You could set the size of the list with the Capacity property to remove the need to resize, but at that point you would do just as well with the array. The need to keep resizing is when a List gains an advantage, but if you can always size it correctly the first time (and aren't adding or removing items later), then an array is at least as good.
    My usual boring signature: Nothing

  3. #3
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Array or List

    List does everything you want more efficiently than an array.

    The "cost" of an array is twofold: ReDim is a reallocation and ReDim Preserve is a reallocation + copy. The only way to mitigate these is to start with a too-big array and keep track of where the "tail" is. That way you do your allocations up-front.

    List does this for you. Its capacity starts at 16, and doubles every time it's exceeded. That's a ReDim Preserve on its internal array, so if you really want to avoid allocations, you can pre-set capacity to a value larger than you expect.

    So if you never expect more than about 50 sensors, use a List with the capacity set to 50. You'll never perform an allocation or a copy!
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Array or List

    Based on what you have said, I would probably write a method that used a List(Of T) internally and then returned an array. That means that, inside the method, the List can grow as required, then the caller of that method gets a fixed-size array once the work is done. If you have no need or intention to add or remove after the method returns then the array is appropriate. When a rescan is done, I would just call the method again and get a new array, discarding the old one.
    vb.net Code:
    1. Private Function GetSenors() As Sensor()
    2.     Dim sensors As New List(Of Sensor)
    3.  
    4.     Do
    5.         '...
    6.  
    7.         sensors.Add(New Sonsor)
    8.     Loop
    9.  
    10.     Return sensors.ToArray()
    11. End Function
    vb.net Code:
    1. sensors = GetSensors()

  5. #5
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Array or List

    I think that's quite possibly the least efficient way to go about it, if we're worried about that.

    Logically speaking, it's easy to write. You didn't mention pre-setting Capacity, but let's go ahead and assume you do. Here's what GetSensors() does if we pre-set Capacity to 50 and add 30 items:
    • Allocate a new 50-element array.
    • Set elements 0-29 to hold a value.
    • Allocate a new 30-element array.
    • Copy elements 0-29 into that array.
    • Throw away the List and its 50-element array.

    For safety, List<T> can't directly give you its internal array. So its ToArray() implementation is a copy.

    List already does the most optimized thing. I understand, philosophically, wanting a fixed-size array for some situations. I find it dogmatic to add all that extra work because "What if I accidentally add a sensor later?" I feel like the right answer is the question, "Why would I add sensors from a different place?"

    If you were really worried about API purity, ReadOnlyCollection is a mostly free wrapper around IList<T> that prevents you from calling any mutating methods. So I'd end up writing something like this if I had some motive to be dogmatic:
    Code:
    Public Class SensorCollection
        Inherits List(Of Sensor)
    
        Public Function ToFixed() As ReadOnlyCollection(Of Sensor)
            Return New ReadOnlyCollection(Of Sensor)(Me)
        End Function
    End Class
    I don't think we're worried about all that. The question was, "Which is better here, and why?"
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  6. #6
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,038

    Re: Array or List

    Having re-read what I wrote....that was some pretty poor English on my part.

    My point is that the example does not Redim the array repeatedly. It sets the size of the array just one time. In that case, an array is the most efficient. If you were calling Redim or Redim Preserve each time through a loop, then the List would be more efficient even without setting the capacity. With setting the capacity, the List would be more efficient still. However, since you are setting the array just one time, then an array is at least as efficient in this case, especially if what you want is the array in the end.

    I'm not too concerned about the copy of moving a list.ToArray, because that would be a fairly efficient block copy (at least I would hope it would be). The cost is likely to be more in the allocation of the memory for the array than the copy. That's a cost I'm often quite willing to bear. After all, exposing a List out of a class allows people to alter it more readily than they can alter an array, and with greater expectation of it mattering.
    My usual boring signature: Nothing

  7. #7

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,753

    Re: Array or List

    I suppose I should expand on why I am asking the question in the first place. Other than simply my curiosity for the "best" solution (I understand that best is generally subjective, but not always in programming), this program that I'm writing hogs a lot of CPU usage with an API that I'm using and I really need to make the program as efficient as possible. So while it may seem trivial, in this situation, I really do need the most efficient solution as possible.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Array or List

    "efficient" is subjective as well. The literal fastest option would be creating an array that is at least as big as you need and simply keeping a separate count of the elements you set. That is literally what would happen if you created a List(Of T) with an initial capacity but without the extra layer. Of course, the extra layer makes your life easier so maybe you're prepared to accept that. Also, if you always create a List with the maximum capacity then you may often end up with an internal array that is much bigger than required and thus you'll use more memory than is strictly necessary. Maybe you're prepared to accept that too. You really need to consider the competing priorities and decide which is most important to you. If you need to do some testing of different options to determine which best meets your requirements then do that. Make sure to vary your test parameters though, because which option appears to best suit your needs in one scenario may not do so in another.

    One option that just occurred to me - and one that is used in various places in the Framework - is to use a ReadOnlyCollection(Of T). The reason that I recommended creating a List internally and then returning an array was because it seems that the intent is not to modify the list after it's returned and an array is less editable that a List(Of T). Even then though, while you cannot change the size of the array, you can still set individual elements. The ReadOnlyCollection(Of T) has two advanatges. Firstly, it wraps the original List(Of T) so there's no need for any reallocation and copying of items. Secondly, not only can you not call Add or Remove but you can also not set an item. That would change my previous code to this:
    vb.net Code:
    1. Private Function GetSenors() As ReadOnlyCollection(Of Sensor)
    2.     Dim sensors As New List(Of Sensor)
    3.  
    4.     Do
    5.         '...
    6.  
    7.         sensors.Add(New Sonsor)
    8.     Loop
    9.  
    10.     Return New ReadOnlyCollection(Of Sensor)(sensors)
    11. End Function
    The one thing missing from there is setting the Capacity of the List(Of T). If you were to do that then it would really be a judgement call. If you make it a ridiculously large value to guarantee that it's always big enough then you're introducing inefficiency there anyway. If you know for a fact what the largest size required would be and you use that then you'll never get a reallocation but you'll often have a larger than required internal array. You have to decide how often and how many reallocations you are prepared to live with. Also note that the internal array of a List(Of T) gets doubled each time it grows, so if you set the Capacity to 1000 and there are 1001 items then the final Capacity will be 2000.

  9. #9
    PowerPoster ChrisE's Avatar
    Join Date
    Jun 2017
    Location
    Frankfurt
    Posts
    3,048

    Re: Array or List

    Hi dday,

    not sure if I understand you situation correctly, also not sure if you want to send the Copy of Array Data to
    another Form.

    here my go...
    Code:
    'in Form1
    Option Explicit On
    Option Strict On
    
    Public Class Form1
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Dim items() As String = {"ChrisE", "Tommy", "Peter"}
            Me.ListBox1.Items.AddRange(items)
            If Me.ListBox1.Items.Count > 0 Then Me.ListBox1.SelectedIndex = 0
            If Me.ListBox1.Items.Count > 0 Then
                ReDim Me._ArrayList(Me.ListBox1.Items.Count - 1)
                '
                Me.ListBox1.Items.CopyTo(Me._ArrayList, 0)
                '
            End If
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim frm As Form = New Form2()
            With frm
                .Text = "Test..."
                .ShowDialog()
            End With
        End Sub
    
        Private _ArrayList() As Object
    
        Public Property ItemList() As Object()
            Get
                Return Me._ArrayList
            End Get
            Set(ByVal value As Object())
                Me._ArrayList = value
            End Set
        End Property
    End Class
    and ...
    Code:
    'in Form2
    Option Explicit On
    Option Strict On
    
    Public Class Form2
    
        Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            If Form1.ItemList.Length > 0 Then
                Array.Sort(Form1.ItemList())
                For n As Integer = 0 To Form1.ItemList().Length - 1
                    Me.ListBox1.Items.Add(Form1.ItemList(n))
                Next
            Else
            End If
        End Sub
    End Class
    or can't you send the Data directly to a Database Table ?

    p.s. your little Bug always makes me smile

    regards
    Chris
    to hunt a species to extinction is not logical !
    since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.

  10. #10
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Array or List

    Quote Originally Posted by jmcilhinney View Post
    One option that just occurred to me - and one that is used in various places in the Framework - is to use a ReadOnlyCollection(Of T)..
    I wonder if it occurred to you because I mentioned it?

    I get why you wrote what you did and in plenty of production code I might do it that way. When n is a reasonable size I care a heck of a lot more about "making it work" than hitting the best performance metrics!

    If we did care about the performance metrics, either a pre-initialized array or a pre-initialied List would be the "fastest", with the added logical costs of "I have to be careful who I share it with". If this were C#, we could also talk about using Span<T>, but this is one of the first VB casualties of "please don't add new language features to VB".
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  11. #11
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Array or List

    Quote Originally Posted by Sitten Spynne View Post
    I wonder if it occurred to you because I mentioned it?
    I don't think so, because I came here to make that post without having read yours. Perhaps I saw your post and absorbed it subconsciously if not consciously. Don't really know. They do say that great minds think alike. I guess you and I do too.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width