Spliting large imported text file into a dynamic 2d array in VB 2015 - vb.net

I am currently trying to code a way to read a text file filled with LOTS of data and create a dynamic 2d array to hold each numeric value in its own cell. The text file has data formatted like this
150.00 0.00030739 0.00030023 21.498 0.00024092
150.01 0.00030778 0.00030061 21.497 0.00024122
150.02 0.00030818 0.00030100 21.497 0.00024151
150.03 0.00030857 0.00030138 21.496 0.00024181
150.04 0.00030896 0.00030177 21.496 0.00024210
150.05 0.00030935 0.00030216 21.496 0.00024239
where the spaces are denoted by a vbTab. This is what I have so far.
Dim strfilename As String
Dim num_rows As Long
Dim num_cols As Long
Dim x As Integer
Dim y As Integer
strfilename = "Location of folder holding file" & ListBox1.SelectedItem
If File.Exists(strfilename) Then
Dim sReader As StreamReader = File.OpenText(strfilename)
Dim strLines() As String
Dim strLine() As String
'Load content of file to strLines array
strLines = sReader.ReadToEnd().Split(Environment.NewLine)
'redimension the array
num_rows = UBound(strLines)
strLine = strLines(0).Split(vbTab)
num_cols = UBound(strLine)
ReDim sMatrix(num_rows, num_cols)
'Copy Data into the array
For x = 0 To num_rows
strLine = strLines(x).Split(vbTab)
For y = 0 To num_cols
sMatrix(x, y) = strLine(y).Trim()
Next
Next
End If
When I run this code I get only the first number in the first column of the array and everything else is missing. I need something that shows all of the values. Any help or guidance would be greatly appreciated
Edit:
Here's a picture of what I'm seeing.
What I'm Seeing

You don't need to read all the data in one lump - you can read it line-by-line and process each line.
I assume that the data is machine-generated so that you know there are no errors. I did however put in a check for the required quantity of items on a line.
I copied the data you gave as an example and edited it to change the spaces to tabs.
Option Strict On
Option Infer On
Imports System.IO
Module Module1
Class Datum
Property Time As Double
Property X As Double
Property Y As Double
Property Z As Double
Property A As Double
Sub New(t As Double, x As Double, y As Double, z As Double, a As Double)
Me.Time = t
Me.X = x
Me.Y = y
Me.Z = z
Me.A = z
End Sub
Sub New()
' empty constructor
End Sub
Overrides Function ToString() As String
Return String.Format("(T={0}, X={1}, Y={2}, Z={3}, A={4}", Time, X, Y, Z, A)
' if using VS2015, you can use the following line instead:
' Return $"T={Time}, X={X}, Y={Y}, Z={Z}, A={A}"
End Function
End Class
Function LoadData(srcFile As String) As List(Of Datum)
Dim data = New List(Of Datum)
Using sr As New StreamReader(srcFile)
While Not sr.EndOfStream()
Dim thisLine = sr.ReadLine()
Dim parts = thisLine.Split({vbTab}, StringSplitOptions.RemoveEmptyEntries)
If parts.Count = 5 Then
data.Add(New Datum(CDbl(parts(0)), CDbl(parts(1)), CDbl(parts(2)), CDbl(parts(3)), CDbl(parts(4))))
End If
End While
End Using
Return data
End Function
Sub Main()
Dim src = "C:\temp\testdata2.txt"
Dim myData = LoadData(src)
For Each datum In myData
Console.WriteLine(datum.ToString())
Next
Console.ReadLine()
End Sub
End Module
As you can see, if you use a class to hold the data then you can usefully give it other methods like .ToString().
Option Strict On makes sure that you do not do anything which is meaningless, like trying to store a string in a numeric data type. It is strongly recommended that you set Option Strict On as the default for all projects.
Option Infer On lets the compiler figure out what data type you want when you use something like Dim k = 1.0, so you don't have to type Dim k As Double = 1.0, but note that if you used Dim k = 1 it would infer k to be an Integer.
Once the data is in instances of a class in a list, you can use LINQ to process it in a fairly easy-to-read fashion, for example you could do
Console.WriteLine("The average X value is " & (myData.Select(Function(d) d.X).Average()).ToString())

Related

Small function to rearrange string array in VBA

I've been writing a macro for Solidworks in VBA, and at one point I'd like to rearrange the sheets in a drawing in the following way--if any of the sheets are named "CUT", bring that sheet to the front. Solidworks API provides a way to rearrange the sheets, but it requires an array of sheet names sorted into the correct order--fair enough. The way to get the sheet names looks to be this method.
So, I tried to write a small function to rearrange the sheets in the way I want. The function call I'm trying to use and the function are shown here
Function Call
Dim swApp As SldWorks.SldWorks
Dim swDrawing As SldWorks.DrawingDoc
Dim bool As Boolean
Set swApp = Application.SldWorks
Set swDrawing = swApp.ActiveDoc
.
.
.
bool = swDrawing.ReorderSheets(bringToFront(swDrawing.GetSheetNames, "CUT"))
Function Definition
Private Function bringToFront(inputArray() As String, _
stringToFind As String) As String()
Dim i As Integer
Dim j As Integer
Dim first As Integer
Dim last As Integer
Dim outputArray() As String
first = LBound(inputArray)
last = UBound(inputArray)
ReDim outputArray(first to last)
For i = first To last
If inputArray(i) = stringToFind Then
For j = first To (i - 1)
outputArray(j + 1) = inputArray(j)
Next j
For j = (i + 1) To last
outputArray(j) = inputArray(j)
Next j
outputArray(first) = stringToFind
End If
Next i
bringToFront = outputArray
End Function
The error I get is "Type mismatch: array or user defined type expected" on the function call line. I've done quite a bit of searching and I think what I'm messing up has to do with static vs dynamic arrays, but I haven't quite been able to get to the solution on my own.
Besides the corrections suggested in the comments, what is happening is that at the lines
bringToFront(j + 1) = inputArray(j)
and
bringToFront(first) = stringToFind
the compiler thinks you are trying to call recursively the function bringToFront. That is why it complains about the number of parameters in the error message. To fix this, just create another array as local array variable, with a different name, let us name it "ret", fill it appropriately, and assign it at the end before returning.
EDIT: Also, it is better to declare the arrays as Variant types to avoid interoperability problems between VB6 and .Net . This was the final issue
Private Function bringToFront(inputArray As Variant, _
stringToFind As String) As Variant
Dim i As Integer
Dim j As Integer
Dim first As Integer
Dim last As Integer
first = LBound(inputArray)
last = UBound(inputArray)
Dim ret() As String
ReDim ret(first To last)
For i = first To last
If inputArray(i) = stringToFind Then
For j = first To (i - 1)
ret(j + 1) = inputArray(j)
Next j
ret(first) = stringToFind
End If
Next i
bringToFront = ret
End Function

Number of indices is less than the number of dimensions of the indexed array in SSRS VBA Code

I have written below Code in SSRS Report and calling it from expression as =Code.convertCode(Parameters!ProcessingStatus.Value,"Reject,Fail")).Value , but on previewing report I am getting the error : "Number of indices is less than the number of dimensions of the indexed array"
Public Function convertCode(ParamValues As String, findString As String) As String()
Dim SrcArray() As String
Dim FndArray() As String
Dim DstArray() As String
Dim i As Integer
Dim j As Integer
Dim k As Integer
SrcArray() = Split(ParamValues, ",")
FndArray() = Split(FindString,",")
For k = LBound(FndArray) To UBound(FndArray)
For i = LBound(SrcArray) To UBound(SrcArray)
If (InStr(SrcArray(i), FndArray(k)) > 0) Then
ReDim Preserve DstArray(j) As String
DstArray(j) = SrcArray(i)
j = j + 1
End If
Next i
Next k
arr = DstArray
End Function
At the end of your function you have
arr = DstArray
which should be
convertCode = DstArray
Not sure if that's already the problem.
Note: Option Explicit would prevent this error.
I think the problem is that you're not declaring the first dimension in your arrays.
Dim SrcArray() As String
Dim FndArray() As String
Dim DstArray() As String
Should be:
Dim SrcArray(10) As String
Dim FndArray(10) As String
Dim DstArray(10) As String
Or whatever the number of the Array you'll need.
The error message indicates that the number of indices you have (none) is less that what you need (variables I, k, j).

permutation not accepting large words

the vb.net code below permutates a given word...the problem i have is that it does not accept larger words like "photosynthesis", "Calendar", etc but accepts smaller words like "book", "land", etc ...what is missing...Pls help
Module Module1
Sub Main()
Dim strInputString As String = String.Empty
Dim lstPermutations As List(Of String)
'Loop until exit character is read
While strInputString <> "x"
Console.Write("Please enter a string or x to exit: ")
strInputString = Console.ReadLine()
If strInputString = "x" Then
Continue While
End If
'Create a new list and append all possible permutations to it.
lstPermutations = New List(Of String)
Append(strInputString, lstPermutations)
'Sort and display list+stats
lstPermutations.Sort()
For Each strPermutation As String In lstPermutations
Console.WriteLine("Permutation: " + strPermutation)
Next
Console.WriteLine("Total: " + lstPermutations.Count.ToString)
Console.WriteLine("")
End While
End Sub
Public Sub Append(ByVal pString As String, ByRef pList As List(Of String))
Dim strInsertValue As String
Dim strBase As String
Dim strComposed As String
'Add the base string to the list if it doesn't exist
If pList.Contains(pString) = False Then
pList.Add(pString)
End If
'Iterate through every possible set of characters
For intLoop As Integer = 1 To pString.Length - 1
'we need to slide and call an interative function.
For intInnerLoop As Integer = 0 To pString.Length - intLoop
'Get a base insert value, example (a,ab,abc)
strInsertValue = pString.Substring(intInnerLoop, intLoop)
'Remove the base insert value from the string eg (bcd,cd,d)
strBase = pString.Remove(intInnerLoop, intLoop)
'insert the value from the string into spot and check
For intCharLoop As Integer = 0 To strBase.Length - 1
strComposed = strBase.Insert(intCharLoop, strInsertValue)
If pList.Contains(strComposed) = False Then
pList.Add(strComposed)
'Call the same function to review any sub-permutations.
Append(strComposed, pList)
End If
Next
Next
Next
End Sub
End Module
Without actually creating a project to run this code, nor knowing how it 'doesn't accept' long words, my answer would be that there are a lot of permutations for long words and your program is just taking much longer than you're expecting to run. So you probably think it has crashed.
UPDATE:
The problem is the recursion, it's blowing up the stack. You'll have to rewrite your code to use an iteration instead of recursion. Generally explained here
http://www.refactoring.com/catalog/replaceRecursionWithIteration.html
Psuedo code here uses iteration instead of recursion
Generate list of all possible permutations of a string

how to shuffle array in VB?

I'm trying to create and application which will shuffle an string array and produce 2 totally different versions where no element will match each other
like for example the initial array is A, B, C, D, E than the shuffled array must be B, D, E, A, C.
In my case when I suffle them and try to produce an output I get shuffled array but they are completely identical to each other. It seems like the values in last array override the values of the previous ones.
I tried to protect them but I don't know how to do it. Please can anybody give me a hint about what am I doing wrong?
Dim myArray() As String = {"A", "B", "C", "D", "E"}
This is the code of the button which triggers shuffle
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RendomOutput1(myArray)
End Sub
End Class
THis is the function that shuffles first array:
Sub RendomOutput1(ByVal x() As String)
Dim t As Integer
Dim Temp As String
For i As Integer = 0 To x.Count - 1
Dim rnd As New Random
t = rnd.Next(0, x.Count - 1)
Temp = x(t)
x(t) = x(i)
x(i) = Temp
Next
RandomOutput2(x)
End Sub
This is the function which produces another array and prints the result:
Sub RendomOutput2(ByRef y() As String)
Dim y1() As String = y' May be I shall lock or somehow protect y1 here?
'Lock(y1) doesn't work
Dim t As Integer
Dim Temp As String
For i As Integer = 0 To y.Count - 1
Dim rnd As New Random
t = rnd.Next(0, y.Count - 1)
Temp = y(t)
y(t) = y(i)
y(i) = Temp
Next
For i As Integer = 0 To x.Count - 1
Label1.Text &= y1(i) & " IS NOT " & y(i) & vbCrLf
Next
End Sub
IN the result arrays y1 and y are different from initial but identical to each other. Does anybody know how can I make them different. Probably lock y1 array or something. Thank you in advance
This line
Dim y1() As String = y
doesn't create a new array - it creates a reference to an existing array. So you'll have two array references (y and y1) but only one array (both references point to the same array). When you make changes to y those changes are visible through y1 because both of them refer to the same underlying array.
What you need is 2 distinct array instances where the data held be the arrays are duplicated (that is, you need 2 array references that point to 2 different arrays). Then changes made to one array will not affect the other array.
For example:
' Create new array from the input array
Dim y1() As String = new String(y.Count-1){}
For i As Integer = 0 To y.Count-1
y1(i) = y(i)
Next i
Alternatively, you can just clone the array:
Dim y1() As String = y.Clone()
Behind the scenes this results in the same thing.
Here's a simple routine for shuffling any array:
Public Sub Shuffle(Of T)(ByRef A() As T)
Dim last As Integer = A.Length - 1
Dim B(last) As T
Dim done(last) As Byte
Dim r As New Random(My.Computer.Clock.TickCount)
Dim n As Integer
For i As Integer = 0 To last
Do
n = r.Next(last + 1)
Loop Until Not done(n)
done(n) = 1
B(i) = A(n)
Next
A = B
End Sub
Note that some elements could remain at their original index by chance.

For loop make new variables for you - VB.Net

I'm trying to make a for loop for will make a new variable for me, every step. I want something like this. What ever step I am on, say, x = 2, it Dims newVar2, if x = 3: Dim newVar3
Is there any way to do that? I was hoping something like, Dim newVar & x would work, but of course now.
I was trying to do it as an array, but I'm not sure how to do that, or ReDimming, so examples would be great!
To create a collection of variable values inside a for loop, you should use a List(Of t) object or something similar (For Example Dictionary).
To do this with a List(Of t) you can do the following :
Dim varList As New List(Of Integer)
For i As Integer = 0 To 10
varList.add(i)
Next
Or if you want to do it with the variable names you mentioned, try :
Dim varList As New List(Of String)
For i As Integer = 0 To 10
varList.add("newVar" & i)
Next
To retrieve the value from a List use the following : Dim result As String = varList(0)
Alternatively you can use a Dictionary object to store Key/Value pairs :
Dim varList As New Dictionary(Of String, Integer)
For i As Integer = 0 To 10
Dim k As Integer = 0
varList.add("newVar" & i, k)
Next
Becareful though as a Dictionary object can only contain unique Keys. To return the value find it as : Dim result As Integer = varList("newVar0")
basic array:
Dim Arr(1000) As Integer
For i As Integer = 0 To 999
Arr(i) = YYYYY
Next
trick for dynamic size:
Dim max As Integer = XXXXXX
Dim Arr(1000) As Integer
For i As Integer = 0 To max
'if too small, Increasing array without loss old data
If Arr.Length = i Then
ReDim Preserve Arr(Arr.Length + 1000)
End If
Arr(i) = YYYYY
Next
or, use list:
Dim max As Integer = XXXXXX
Dim list As New List(Of Integer)
For i As Integer = 0 To max
list.Add(YYYYY)
Next
The other answers are technically correct, but you probably don't need the iteration loops. You can probably do this in a single line of code:
Dim varList As Dictionary(Of String, String) = Enumerable.Range(0, 10).ToDictionary(Function(k) "newVar" & k, Function(v) "Some value for newVar" & v)
Dim myInts As New List(Of Int)
For i = 0 To 10
myInts.Add(i)
Next