-
Jan 18th, 2018, 04:53 PM
#1
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
-
Jan 18th, 2018, 05:27 PM
#2
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
-
Jan 18th, 2018, 06:11 PM
#3
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.
-
Jan 18th, 2018, 06:23 PM
#4
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:
Private Function GetSenors() As Sensor() Dim sensors As New List(Of Sensor) Do '... sensors.Add(New Sonsor) Loop Return sensors.ToArray() End Function
-
Jan 19th, 2018, 11:59 AM
#5
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.
-
Jan 19th, 2018, 12:24 PM
#6
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
-
Jan 19th, 2018, 04:25 PM
#7
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.
-
Jan 19th, 2018, 09:14 PM
#8
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:
Private Function GetSenors() As ReadOnlyCollection(Of Sensor) Dim sensors As New List(Of Sensor) Do '... sensors.Add(New Sonsor) Loop Return New ReadOnlyCollection(Of Sensor)(sensors) 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.
-
Jan 20th, 2018, 10:11 AM
#9
Re: Array or List
Originally Posted by jmcilhinney
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.
-
Jan 20th, 2018, 10:17 AM
#10
Re: Array or List
Originally Posted by Sitten Spynne
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.
-
Jan 20th, 2018, 06:23 AM
#11
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.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|