Object reference not set to an instance of an object while assinging value to byte object - vb.net

I am trying to read byte array and i want to store first value of array in list. I tried one small console application example but i got above issue. I searched a lot on internet but didnt get answer
Sub Main()
Dim lData As New List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
Dim a() As Byte
For ReadValue As Integer = 0 To lBuffer.Length
a(0) = lBuffer(ReadValue)
Exit For
Next
lData.AddRange(a)
End Sub

Your problem here is that you have declared the array but you have not initialized it. By declaring a variable with Dim a() As Byte, you have said "This thing exists and here's what it looks like". However, you haven't actually provided anything that will occupy the definition of a(), or in other words you haven't instantiated it yet.
Think of it this way. I tell you that apples exist and that they look like oddly shaped red orbs, there are seeds inside of them, and they are edible. Now I'm going to tell you to take all of the seeds out of the apple and eat the apple. Picking seeds out of an apple is completely possible, and eating apples is also possible. One problem though, you can't do what I told you. Why? Because I never gave you an apple to do those things with.
To be more specific in regards to you question, You have created an array of bytes with Dim a() As Byte. That's the first step, you told it "Hey, this is going to be a collection of things and all of those things are going to be a Byte". The main problem with arrays in the way you used it is that arrays need to know how big they are when you use them. So you have two options, you can either a) declare the array with a size which will create an empty array where all elements are null or b) you can do it like you did and then assign an array that has already been defined to it.
I'll give you examples of both the methods:
Sub Main()
Dim lData As New List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
' Tell the array how big to be in the first place
Dim a(lBuffer.Length - 1) As Byte
For ReadValue As Integer = 0 To lBuffer.Length - 1
a(ReadValue) = lBuffer(ReadValue)
Next
lData.AddRange(a)
End Sub
Sub Main()
Dim lData As New List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
Dim a() As Byte
' Lets create a temporary list and then use the .ToArray function
' which will return an already instantiated array.
Dim byteList as new List(of Byte)
For ReadValue As Integer = 0 To lBuffer.Length - 1
' Add each item to the list
byteList.Add(lBuffer(ReadValue))
Next
' Now, convert the list to an array and set it to a()
a = byteList.ToArray
lData.AddRange(a)
End Sub
Either of those options should stop the NullReferenceException error you are receiving. However you already have a List(of Byte) defined and instantiated, so the easiest option would probably be just assigning the values to the list directly:
Sub Main()
Dim lData As New List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
For ReadValue As Integer = 0 To lBuffer.Length - 1
lData.Add(lBuffer(ReadValue))
Next
End Sub
Or even shorter code would be to use a Lambda expression:
Sub Main()
Dim lData As New List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
lBuffer.ToList.ForEach(Sub(x) lData.Add(x))
End Sub
However the shortest possible answer to achieve the same thing would be to use the .ToList extension directly:
Sub Main()
Dim lData As List(Of Byte)
Dim lBuffer() As Byte = {5, 99, 4, 7}
lData = lBuffer.ToList()
End Sub
After re-reading this, I thought of an even shorter version. You can cut out the middleman of the byte array completely and just instantiate the List(Of Byte) from your array list.
Sub Main()
Dim lData As New List(Of Byte) From {5, 99, 4, 7}
End Sub
And I believe that's the shortest possible way to do it. If someone can prove me wrong though, I'd love to learn.

Related

New to programming language, need help to read a .dat file into array Vs VB, console .net framework

I am trying to read from a data file called TXT.dat and store the circled values into a separate array's using the type of commands I have used. I cannot use streamreader,streamwriter this is what I am learning at university but we were taught to read an array not certain values as I will be tested using a file which has
2 factorial values from a single file and store int two arrays.
I have spent hours trying before going to paid sites who always answer with i/o streamreader which doesnt help
.dat file i created to practice
MY CODE
Sub Main()
Const i_val As Integer = 6
Dim j As Integer = 6 'loop readers
Dim Arayn_Fact(i_val - 1) As Double 'array for 2nd value per line
Dim Aray_Fact2n(j - 1) As Double 'array for 4th value per line
Read_Values(i_val - 1, Arayn_Fact)
End Sub
Sub Read_Values(ByVal i As Integer, ByRef _A() As Double)
Dim fid1 As Integer = FreeFile()
Dim fid2 As Integer = FreeFile() + 1
Dim tmp As Double
FileOpen(fid1, "TXT.dat", OpenMode.Input, OpenAccess.Read)
For i = 0 To 5 Step 1
Input(fid1, tmp)
Input(fid1, _A(i))
Next i
FileClose(fid1)
Console.ReadKey()
End Sub
Without getting too fancy, here's some very basic code to do what you've outlined:
Sub Main()
Dim fileName As String = "txt.dat"
Dim Aray_Fact2() As Integer 'array for 2nd value per line
Dim Aray_Fact4() As Integer 'array for 4th value per line
Dim list2 As New List(Of Integer)
Dim list4 As New List(Of Integer)
Dim lines() As String = System.IO.File.ReadAllLines(fileName)
For Each line As String In lines
Dim values() As String = line.Split(",")
If values.Length >= 3 Then
Dim f2, f4 As Integer
If Integer.TryParse(values(1), f2) AndAlso Integer.TryParse(values(3), f4) Then
list2.Add(f2)
list4.Add(f4)
Else
Console.WriteLine("Invalid value in line: " & line)
End If
Else
Console.WriteLine("Invalid number of entries in line: " & line)
End If
Next
Aray_Fact2 = list2.ToArray
Aray_Fact4 = list4.ToArray
Console.WriteLine("Aray_Fact2: " & String.Join(",", Aray_Fact2))
Console.WriteLine("Aray_Fact4: " & String.Join(",", Aray_Fact4))
Console.Write("Press Enter to Quit...")
Console.ReadLine()
End Sub
If you are completely against the use of Lists and ToArray, then you'd have to read the file TWICE. Once to determine how many lines are in the file so you can dimension the arrays to the correct size. Then another time to actually read the values and populate the arrays.
First, some style things. Passing the array ByRef is incorrect. Arrays are already reference types, and so passing ByVal still passes the reference to the array object. But don't even pass the array in the first place. It's better practice to let the Read_Values() method create and return the array to the calling function.
And no one uses that ancient/ganky FileOpen() API anymore. I mean that. NO. ONE. It's not even appropriate for teaching, as the Stream types are closer to what the low level operating system/file system are doing. If you can't use StreamReader and friends, there are still better options out there.
Sub Main()
Dim Array_Fact() As Double = Read_Values("TXT.dat", 1)
Dim Array_Fact2n() As Double = Read_Values("TXT.dat", 3)
Console.ReadKey(True)
End Sub
Function Read_Values(filePath As String, position As Integer) As Double()
Dim lines() As String = File.ReadAllLines(filePath) 'Look Ma, no StreamReader
Dim result(lines.Length - 1) As Double
For i As Integer = 0 To Lines.Length - 1
result(i) = Double.Parse(lines(i).Split(",")(position).Trim())
Next line
Return result
End Function
But what I'd really do is keep the 2nd and 4th values in the same collection and read everything in one pass through the file. This uses features like Generics, Tuples, Lambdas+Linq, and more that you won't get to for some time, but I feel like it's useful to show you where you're going:
Sub Main()
Dim Facts = Read_Values("TXT.dat")
Console.WriteLine(String.Join(",",Facts.Select(Function(f) $"({f.Item1}:{f.Item2})")))
Console.ReadKey(True)
End Sub
Function Read_Values(filePath As String) As IEnumerable(Of (Double, Double))
Return File.ReadLines(filePath).Select(
Function(line) 'Poor man's CSV. In real code, I'd pull in a CSV parser from NuGet
Dim fields = line.Split(",")
Return (Double.Parse(fields(1).Trim()), Double.Parse(fields(3).Trim()))
End Function
)
End Function

Convert integer array to string array

whats the easiest way to convert an array of integers into string form? I'm trying to copy the whole array of integers into strings.
{1, 2, 3}
to
{"1", "2", "3"}
The easiest method would be to use the Select extension method which is provided by LINQ:
Dim intArray() As Integer = {1, 2, 3}
Dim strArray() As String = intArray.Select(Function(x) x.ToString()).ToArray()
If you don't want to, or cannot use LINQ, you can use the Array.ConvertAll method, which is almost as easy:
Dim strArray() As String = Array.ConvertAll(Of Integer, String)(intArray, Function(x) x.ToString())
EDIT
Based on your comments, below, it looks like you need to convert from an ArrayList of integers to an ArrayList of strings. In that case, you could do it like this:
Dim intArray As New ArrayList({1, 2, 3})
Dim strArray As New ArrayList(intArray.ToArray().Select(Function(x) x.ToString()).ToArray())
Although, at that point, it's starting to get a bit messier. It's probably easier to just do a standard loop, like this:
Dim myArray As New ArrayList({1, 2, 3})
For i As Integer = myArray.Count - 1 To 0 Step -1
myArray(i) = myArray(i).ToString()
Next
For what it's worth, though, unless you are still on a really old version of the .NET Framework, you really ought to be using the List(Of T) class rather than the ArrayList class, in most cases.

VB.NET - Array of Integers needs to be instantiated, how to?

First try
Dim holdValues() As Integer 'Doesn't Work
holdValues(1) = 55
Second try
Dim holdValues(-1) As Integer 'Gives me Index was outside the bounds of the array.
holdValues(1) = 55
I'm trying to do something similar to
Dim myString(-1) As String
But apparently this doesn't apply to integer arrays. I don't know what the size of the array will be, it wont get smaller but it will grow larger.
Any help will be appreciated, thank you!
You could use the Initializers shortcut:
Dim myValues As Integer() = New Integer() {55, 56, 67}
But if you want to resize the array, etc. then definately have a look at a List(Of Integer):
'Initialise the list
Dim myValues As New System.Collections.Generic.List(Of Integer)
'Shortcut to pre-populate it with known values
myValues.AddRange(New Integer() {55, 56, 57})
'Add a new value, dynamically resizing the array
myValues.Add(32)
'It probably has a method do do what you want, but if you really need an array:
myValues.ToArray()
you add the number to
holdValues(x) //x+1 will be size of array
so something like this
Dim array(2) As Integer
array(0) = 100
array(1) = 10
array(2) = 1
you can re-allocate the array to be bigger if needed by doing this.
ReDim array(10) as Integer
you'll have to add in your code when you should make your array bigger. You can also look into lists. Lists take care of this issue automatically.
here's some info on Lists: http://www.dotnetperls.com/list-vbnet
Hope this helps.
Also a link for general knowledge on arrays http://www.dotnetperls.com/array-vbnet

VB.NET: Value of Type 'Integer' cannot be converted to 'System.Array'

In the below code I am getting the following error on line If (Not hash.Add(Numbers(Num))) Then Value of Type 'Integer' cannot be converted to 'System.Array'. What am I doing wrong?
Module Module1
Sub Main()
Dim array() As Integer = {5, 10, 12, 8, 8, 14}
' Pass array as argument.
Console.WriteLine(findDup(array))
End Sub
Function findDup(ByVal Numbers() As Integer) As Integer
Dim hash As HashSet(Of Array)
For Each Num In Numbers
If (Not hash.Add(Numbers(Num))) Then
Return (Num)
End If
Next
End Function
End Module
Inside findDup, this
Dim hash As HashSet(Of Array)
Should be
Dim hash As HashSet(Of Integer)
EDIT: As suggested by #Damien_The_Unbeliever, the code
This line
If (Not hash.Add(Numbers(Num))) Then
Should be
If (Not hash.Add(Num)) Then
You have created a hashset of Array, rather than a hashset of Integer. You could change it to Integer, and alter how you try to add things in your loop to:
Function findDup(ByVal Numbers() As Integer) As Integer
Dim hash As New HashSet(Of Integer)
For Each Num In Numbers
If (Not hash.Add(Num)) Then
Return (Num)
End If
Next
End Function
I am hoping you realize that it will only ever find the first duplicate, and doesn't return a value of any type if it doesn't find a duplicate.
You've declared hash to be HashSet(Of Array), which means that it holds arrays. But you're trying to add integers to it.
You need to either change its declaration (HashSet(Of Integer)) or change the call to Add (Add(Numbers)).
Which solution you use will depend on your intent. My guess is that you want to change the type of hash.
Is this what you mean to do?
Sub Main()
Dim someArray() As Integer = {5, 10, 12, 8, 7, 8, 8, 10, 14, 10}
' Pass array as argument.
Dim foo As List(Of Integer) = findDups(someArray)
'foo contains a list of items that have more than 1 occurence in the array
End Sub
Function findDups(ByVal Numbers() As Integer) As List(Of Integer)
Dim rv As New List(Of Integer)
For idx As Integer = 0 To Numbers.Length - 1
If Array.LastIndexOf(Numbers, Numbers(idx)) <> idx Then
If Not rv.Contains(Numbers(idx)) Then rv.Add(Numbers(idx))
End If
Next
Return rv
End Function

Array intersection function speed

I've written a short function for array intersection and wanted to know why one function is faster than the other.
1)
Dim list2() As String 'Assume it has values'
Dim list2length As Integer = list2.length
Function newintersect(ByRef list1() As String) As String()
Dim intersection As New ArrayList
If (list1.Length < list2length) Then
'use list2'
For Each thing As String In list2
If (Array.IndexOf(list1, thing) <> -1) Then
intersection.Add(thing)
End If
Next
Else
'use list1'
For Each thing As String In list1
If (Array.IndexOf(list2, thing) <> -1) Then
intersection.Add(thing)
End If
Next
End If
Return intersection
End Function
2)
Dim list2() As String 'Assume it has values'
Dim list2length As Integer = list2.length
Function newintersect(ByRef list1() As String) As String()
Dim intersection As New ArrayList
If (list1.Length > list2length) Then 'changed >'
'use list2'
For Each thing As String In list2
If (Array.IndexOf(list1, thing) <> -1) Then
intersection.Add(thing)
End If
Next
Else
'use list1'
For Each thing As String In list1
If (Array.IndexOf(list2, thing) <> -1) Then
intersection.Add(thing)
End If
Next
End If
Return intersection
End Function
3)
Dim list2() As String 'Assume it has values'
Dim list2length As Integer = list2.length
Function newintersect(ByRef list1() As String) As String()
For Each thing As String In list1
If (Array.IndexOf(list2, thing) <> -1) Then
intersection.Add(thing)
End If
Next
Return intersection
End Function
So for my testcase, 1 take 65 seconds, 3 takes 63 seconds, while 2 actually takes 75 seconds. Anyone know why 3 is the fastest? And why is 1 faster than 2?
(Sorry about the poor formatting...can't seem to paste it right)
That's not much of a difference. Also, it doesn't seem like the methods would produce the same result, so it would be pointless to compare the performance, right?
Anyhow, the Array.IndexOf is not very efficient way to find items, and doesn't scale well. You should get a dramatic improvement if you use a hash key based collection as lookup instead, something like this:
Function newintersect(ByRef list1 As String(), ByRef list2 As String()) As String()
Dim smaller As HashSet(Of String)
Dim larger As String()
If list1.Length < list2.Length Then
smaller = New HashSet(Of String)(list1)
larger = list2
Else
smaller = New HashSet(Of String)(list2)
larger = list1
End If
Dim intersection As New List(Of String)
For Each item As String In larger
If smaller.Contains(item) Then
intersection.Add(item)
End If
Next
Return intersection.ToArray()
End Function
I'd expect you'd find that with different test cases you can reverse the results you had above and reach a situation where 2 is fastest and 1 & 3 are slower.
It's difficult to comment without knowing the make-up of the test case, it'll depend on the location of 'intersecting' items within the two arrays - if these tend to be close the to front on one array and closer to the end of another then the nesting order of the array iteration / IndexOf will have markedly different performance.
BTW - there are better ways of performing an intersection - sorting one or other array and performing a BinarySearch is one means - using a Dictionary(Of String, ...) or similar is another - and either would result in far better performance.
This is from the MSDN documentation
Dim id1() As Integer = {44, 26, 92, 30, 71, 38}
Dim id2() As Integer = {39, 59, 83, 47, 26, 4, 30}
' Find the set intersection of the two arrays.
Dim intersection As IEnumerable(Of Integer) = id1.Intersect(id2)
For Each id As Integer In intersection
Debug.WriteLine(id.ToString)
Next