So I am building a stock info retrieval program, and I have a good bit of it done so far. Right now I have it return the price from the Yahoo Finance API by singling out the price in the returned API data and then shove it in a listbox with the stock symbol and price. That part works great, but I want to take it a step further now and be able to do what I want with other parts of that returned data. The normal format for the data is:
"<symbol>", <price>, "<date>", "<time>", etc.
If you take a look at my code, right now I have a Getstockinfo function that retrieves the full API output and converts each object(symbol, price, etc) into a new stringbuilder line, and then separates the lines by the commas using the ModifyLine function.
I want to now get the GetStockInfo to return an array, which would allow me to use that array as I pleased outside of that function(in eventhandlers, etc.)
ANY help would be much appreciated!
Public Function GetStockInfo(ByVal pstrSymbol As String) As String
Dim strURL As String
Dim strApiOutput As String
'Yahoo API
strURL = "http://quote.yahoo.com/d/quotes.csv?" & _
"s=" & pstrSymbol & _
"&d=t" & _
"&f=sl1d1t1c1ohgvj1pp2wern"
strApiOutput = RequestWebData(strURL)
'Create stringbuilder(easier to append, replace and insert data)
Dim strReturn As New System.Text.StringBuilder
'Seperate API output into different lines by using LineFeed
For Each strLine As String In strApiOutput.Split(ControlChars.Lf)
'makes sure line actually exists, if so, seperate and add to array using ModifyLine function
If strLine.Length > 0 Then
strReturn.Append(ModifyLIne(strLine) & Environment.NewLine)
End If
Next
Return strReturn.ToString
End Function
Private Function ModifyLIne(ByVal strLine As String) As String
Dim arrLine() As String
'Splits lines by the commas(the normal api output is as follows: <Obj1>, <Obj2>, <Obj3>, etc
'with Intermediary quotes here and there for certain objects such as Company Name
arrLine = strLine.Split(","c)
decStockPrice = CDec(arrLine(1))
Return decStockPrice.ToString
End Function
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim strSymbol As String = txtSymbol.Text
lstStocks.Items.Add(strSymbol.ToUpper() & " - " & GetStockInfo(strSymbol))
End Sub
I want to take it a step further now and be able to do what I want with other parts of that returned data This will do what you want, just not how you want (arrays are old-school)
Class StockQuote
Public Symbol As String
Public Price As Decimal
Public QuoteDate As DateTime
' etc
End Class
Friend myQuotes As New List(of StockQuote)
Then after you get a quote and determine you want to save it (are you saving all of them?):
Dim SQ as New StockQuote
With SQ
.Symbol = arrLine(0) ' so you can pass an array or list of ticker syms
.Price = Convert.ToDecimal(arrLine(1))
' not much sense saving Time and Date as sep items
' if you are getting multiple quotes for a day (vs ending)
.QuoteDate = combine arrline(2) and arrLine(3) ?
etc
End SQ
myQuotes.Add(SQ)
Now, myQuotes will have a list of all the quotes for all the symbols. Get them like you populated it: txtSym.Text = myQuotes(N).Symbol
Related
The objective of the program is to interpret hockey statistics from a file using StreamReader and then display an added column of points. The following code kinda does so, however it’s ineffective in the sense that it doesn’t add the points value to the array - it separately outputs it. Looking for assistance as to how it would be possible to incorporate the points value into aryTextFile();
Dim hockeyFile, LineOfText, aryTextFile() As String
Dim i As Integer
Dim nameText(), NumberText(), goalsText(), assistsText(), GamesWonText() As String
Dim IntAssists(), IntGoals(), PointsText() As Single
hockeyFile = "C:\Users\Bob\Downloads\hockey.txt" 'state location of file
Dim objReader As New System.IO.StreamReader(hockeyFile) 'objReader can read hockeyFile
For i = 0 To objReader.Peek() <> -1 'reads each line seperately, ends when there is no more data to read
LineOfText = objReader.ReadLine 'stores seperate lines of data in HockeyFile into LineofText
aryTextFile = LineOfText.Split(",") 'takes lines and converts data into array
Name = aryTextFile(0) 'first piece of data in lines of text is the name
nameText(i) = aryTextFile(0)
If nameText(0) = "Name" Then
TextBox1.Text = LineOfText & ", Points." & vbCrLf 'displays first line fo text and adds "Points" label
End If
If Name <> "Name" Then 'when second line starts, then begin to intepret data
NumberText(i) = aryTextFile(1)
assistsText(i) = aryTextFile(2) 'assists are in third value of array
goalsText(i) = aryTextFile(3) 'goals are in fourth value of array
GamesWonText(i) = aryTextFile(4)
IntAssists(i) = Val(assistsText(i)) 'since our assists value is a string by default, it must be converted to a integer
IntGoals(i) = Val(goalsText(i)) 'since our goals value is a string by default, it must be converted to a integer
PointsText(i) = (IntGoals(i) * 2) + (IntAssists(i)) 'goals are two points, assists are one point
TextBox1.Text = TextBox1.Text & NumberText(i) & assistsText(i) & goalsText(i) & GamesWonText(i) & PointsText(i) & vbCrLf 'Displays points as last value in each line
End If
Next i
This should get you pretty close:
It'll need extra validation. It doesn't take into account whatever value you have between the name and the goals.
Private Sub ProcessHockeyStats()
Try
Dim inputFile As String = "c:\temp\hockey.txt"
Dim outputFile As String = "c:\temp\output.txt"
If Not File.Exists(inputFile) Then
MessageBox.Show("Missing input file")
Return
End If
If File.Exists(outputFile) Then
File.Delete(outputFile)
End If
Dim lines() As String = File.ReadAllLines(inputFile)
Dim output As List(Of String) = New List(Of String)
Dim firstLine As Boolean = True
For Each line As String In lines
Dim values() As String = line.Split(","c)
Dim points As Integer
If firstLine Then
output.Add("Name, Assists, Goals, Points")
firstLine = False
Else
'needs validation for values
points = CInt(values(1) * 2) + CInt(values(2))
output.Add(String.Concat(line, ",", points))
End If
Next
File.WriteAllLines("c:\temp\outfile.txt", output)
Catch ex As Exception
MessageBox.Show(String.Concat("Error occurred: ", ex.Message))
End Try
End Sub
VS2008 is ancient, especially when later versions of Visual Studio are free. I felt like showing an implementation using more-recent code. Like others, I strongly support building a class for this. The difference is my class is a little smarter, using the Factory pattern for creating instances and a Property to compute Points as needed:
Public Class HockeyPlayer
Public Property Name As String
Public Property Number As String
Public Property Assists As Integer
Public Property Goals As Integer
Public Property Wins As Integer
Public ReadOnly Property Points As Integer
Get
Return (Goals * 2) + Assists
End Get
End Property
Public Shared Function FromCSVLine(line As String) As HockeyPlayer
Dim parts() As String = line.Split(",")
Return New HockeyPlayer With {
.Name = parts(0),
.Number = parts(1),
.Assists = CInt(parts(2)),
.Goals = CInt(parts(3)),
.Wins = CInt(parts(4))
}
End Function
End Class
Dim hockeyFile As String = "C:\Users\Bob\Downloads\hockey.txt"
Dim players = File.ReadLines(hockeyFile).Skip(1).
Select(Function(line) HockeyPlayer.FromCSVLine(line)).
ToList() 'ToList() is optional, but I included it since you asked about an array
Dim result As New StringBuilder("Name, Number, Assists, Goals, Wins, Points")
For Each player In players
result.AppendLine($"{player.Name}, {player.Number}, {player.Assists}, {player.Goals}, {player.Wins}, {player.Points}")
Next player
TextBox1.Text = result.ToString()
I was gonna give you VS 2008 version afterward, but looking at this, the only thing here you couldn't do already even by VS 2010 was string interpolation... you really should upgrade.
Parallel arrays are really not the way to handle this. Create a class or structure to organize the data. Then create a list of the class. The list can be set as the DataSource of a DataGridView which will display your data in nice columns with headings matching the names of your properties in the Hockey class. You can easily order your data in the HockeyList by any of the properties of Hockey.
Public Class Hockey
Public Property Name As String
Public Property Number As String
Public Property Goals As Integer
Public Property Assists As Integer
Public Property Points As Integer
Public Property GamesWon As Integer
End Class
Private HockeyList As New List(Of Hockey)
Private Sub FillListAndDisplay()
Dim path = "C:\Users\Bob\Downloads\hockey.txt"
Dim Lines() = File.ReadAllLines(path)
For Each line As String In Lines
Dim arr() = line.Split(","c)
Dim h As New Hockey()
h.Name = arr(0)
h.Number = arr(1)
h.Assists = CInt(arr(2).Trim)
h.Goals = CInt(arr(3).Trim)
h.GamesWon = CInt(arr(4).Trim)
h.Points = h.Goals * 2 + h.Assists
HockeyList.Add(h)
Next
Dim orderedList = (From scorer In HockeyList Order By scorer.Points Ascending Select scorer).ToList
DataGridView1.DataSource = orderedList
End Sub
First of all I would like to thank anyone willing to help ahead of time. My issue here is that when I attempt to populate my listbox with items in my array, I am getting only "General" added as a listbox item instead of the actual strings in the array. I'm rather new to programming so I apologize if this is an obvious error in my code, although I'm assuming it probably is.
This is my code:
Private Sub frmSalesSummary_Load(sender As Object, e As EventArgs) Handles
MyBase.Load
Dim info() As String = IO.File.ReadAllLines("info.txt")
Dim splitChar As Char = ","
Dim infoString As String
For i = 0 To info.GetUpperBound(0)
infoString = info(i).Split(splitChar)
lstSummary.Items.Add(infoString(i))
Next
End Sub
The text file contains this for testing "alex,General,7,$105.00" on the first line.
There may be frequent edits to this question as I am actively trying to figure this out myself as well. Apologies.
'info' is your line (comma delimited)
'infoString' is an array of the words that are separated by the Split
So if you want to add a single item from that split you would use
infoString(0) for the name, infoString(1) for the Rank, etc...
So you're taking each line, splitting it and to add the name to the listbox you only need to add infoString(0) because that element of the array holds the name from splitting it out from the line.
Try
lstSummary.Items.Add(infoString(0))
If you're wanting a list like:
alex
General
7
$105.00
You could create another loop inside your current loop and use the iterator for the index.
For i = 0 to info.GetUpperbound(0)
infoString = info(i).Split(splitChar)
For x = 0 to infoString.GetUpperBound(0)
lstSummary.Items.Add(infoString(x))
Next
Next
This would take each Line, split it and then add the info from each line to the listbox... Keep in mind, you would have the 4 you showed, then the next line would put the next 4 pieces of information until you run out of lines in your text file.
Still not quite sure if that is exactly what you're trying to do, if this still isn't the case, you might mock up some picture of what you're expecting along with information as to whether or not there is more of this information in the text file.
A small tip. You should never use controls to store the data you're using. Store it as a list of PersonDetails objects, or whatever you want to call them.
You can declare the PersonDetails object like this ..
Private Class PersonDetails
Public Property Name As String
Public Property Category As String
Public Property Type As Integer
Public Property Amount As Decimal
End Class
And the list of them like this
Dim PersonSummaryList As New List(Of PersonDetails)
Your form load event reads the text file and for each line, creates a new PersonDetails object and adds it to the list of PersonDetails and then adds the names to a ListBox
Private Sub frmSalesSummary_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim info() As String = IO.File.ReadAllLines("info.txt")
Dim splitChar As Char = ","c
Dim infoString() As String
For i As Integer = 0 To info.GetUpperBound(0)
infoString = info(i).Split(splitChar)
'remove the commas and $ signs
infoString(3) = infoString(3).Replace("$"c, "")
Dim newPerson As New PersonDetails
newPerson.Name = infoString(0)
newPerson.Category = infoString(1)
newPerson.Type = Integer.Parse(infoString(2))
Decimal.TryParse(infoString(3), newPerson.Amount)
PersonSummaryList.Add(newPerson)
Next
End Sub
In your ListBox, all you will see is a list of names, and when you click on an item, the code below will find the object that matches the name you selected and display whatever properties you want in a MessageBox, but of course you can do whatever you want with the tempPerson object.
Private Sub LstSummary_SelectedIndexChanged(sender As Object, e As EventArgs) Handles LstSummary.SelectedIndexChanged
Dim tempPerson As PersonDetails = PersonSummaryList.Find(Function(x) x.Name = LstSummary.SelectedItem.ToString)
MessageBox.Show("Name :" & tempPerson.Name & vbCrLf & "Amount :" & tempPerson.Amount)
End Sub
I'm using VB.NET 2010 and have been trying to wrap my head around implementing a search feature using a sequential file. Originally I was trying to use a sequential file to read from and search but that has proven to be extremely difficult so I've taken a simple approach using two different arrays with data and try to search through Artist and Album.
The code below takes input from txtSearch.Text which will be for search by artist. I have a duplicate artist "TeeBee" but when I search for that artist I only receive one result instead of two as there are two different albums under the artist "TeeBee".
I thought about adding another loop but it doesn't work. I also thought that the results were getting cut off as there isn't a way to add a return to the results to continue on.
I'm a beginner to programming so please keep that in mind.
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
' Artist array
Dim strArtist() As String = {"Dillinja", "TeeBee", "Dieselboy", "TeeBee"}
' Album array
Dim strAlbum() As String = {"Untitled", "Scorpion", "Horns", "Blades"}
Dim strSearchForArtist As String
Dim intSub As Integer
' artist search
strSearchForArtist = txtSearch.Text
Do Until intSub = strAlbum.Length OrElse
strSearchForArtist = strArtist(intSub)
intSub = intSub + 1
Loop
If intSub < strArtist.Length Then
lstLibrary.Items.Add(strArtist(intSub) & " " & strAlbum(intSub) & vbNewLine)
Else
MessageBox.Show("Invalid", "Bad", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End Sub
Attempt to load text file into array but it doesn't create separate arrays like album, artist genre. - 11-19-14
Private Sub btnLoadArray_Click(sender As Object, e As EventArgs) Handles btnLoadArray.Click
Dim filePath As String = "library.txt"
Dim sr As IO.StreamReader
sr = IO.File.OpenText(filePath)
' look inside file and read every line
' this will be how we put the number for
' our array below
Dim TotalLines As Integer = 0
Dim word As String = ""
' need 3 to be dynamic so we get all lines in the file to build the array words(#)
' wanted to use words(,) but that does not work
Dim words() As String = IO.File.ReadAllLines(filePath)
Dim i As Integer = 0
' when the peak value is -1 we're at the end of the file
Do Until sr.Peek = -1
' load one at a time
word = sr.ReadLine()
' load word into array
words(i) = word
' output
lstArtist.Items.Add(words(i))
' increment counter
i += 1
Loop
'close the file
sr.Close()
End Sub
Well, instead of using arrays and handle all the complications I really suggest you to have a more object oriented approach
So start defining a class to keep the info for an Album like this
Public Class Album
Public ArtistName as String
Public AlbumTitle as String
Public Function ToString() as String
return ArtistName & " - " & AlbumTitle
End Function
End Class
Now you could remove the array mess using a List(Of Album) and asking to each item of this list to render its content via the ToString method.
Also an important role here is reserved to the IEnumerable function Where that extract from the List(Of Album) all the elements that respects the Lambda expression required by the Where method.
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
' Here the list is fixed but you can easily build it loading data from a database
' or from some other storage medium like a file etc...
Dim albumList = new List(Of Album) From _
{
new Album With { .ArtistName = "Dillinja", .AlbumTitle = "Untitled" },
new Album With { .ArtistName = "TeeBee", .AlbumTitle = "Scorpion"},
new Album With { .ArtistName = "Dieselboy", .AlbumTitle = "Horns" },
new Album With { .ArtistName = "TeeBee", .AlbumTitle = "Blades" }
}
' To help search you could integrate the ToLower expressions in
' Plutonix answer here...
Dim searchTerm = txtSearch.Text
Dim searchResult = albumList.Where(Function(x) x.ArtistName = searchTerm)
lstLibrary.Items.Clear()
if searchResult.Count > 0 Then
For Each item in searchResult
lstLibrary.Items.Add(item.ToString())
Next
Else
MessageBox.Show("Not found")
End if
End Sub
Rather than arrays, a List(of String) is easier to manage and provides more efficiency and the kind of functions you probably want.
Private Artists As New List(of String)
....
Artists.Addrange({"Dillinja", "TeeBee", "Dieselboy", "TeeBee"})
...
' find a single item:
If Artists.Contains(txtSearch.Text) Then ' no looping required
' a dupe
Else
' not a dupe
End If
To get all the matching items:
Dim find = Artists.Where(Function(s) _
s.ToLowerInvariant = txtSearch.Text.ToLowerInvariant).ToList
The resulting find will also be a List(of String) containing the matching item. This time it is case insensitive. To get the count of dupes:
Dim finds = Artists.LongCount(Function(n) n.ToLowerInvariant = _
txtSearch.Text.ToLowerInvariant.ToLowerInvariant)
I dont know how much value either can be. Neither 2 nor a List of "Teebee", "TeeBee" is very useful or interesting. More typically, you want the return to be the entire object (like an album) associated with the search term. This requires a Class which glues Arist, Album, Genere, Tracks etc together though (see Steve's answer for a start on this part).
As for the whole file part, the list(s) can be easily serialized allowing an entire list to be saved or reloaded from disk in 2-3 lines of code.
I am working on a windows form application, and I have it reading a text file that has information stored in the form of a table. It looks somewhat like this:
ID Name URL
1 client1 client1.com
2 client2 client2.com
3 client3 client3.com
And so on...
What I need to do is get this data to be read from a stream reader, that throws it into a string, including vbtabs and newlines, and then create an array out of that information, so that it acts as a table that I can then later pull information from based on the column names (i.e. ID, Name, URL) and the ID number. I do not have a lot of experience with arrays, so I was hoping to get some help here as how to do this.
The code I have so far for this functionality is:
Dim readCLientTxtListReader As New StreamReader(strReplicationDataClientAccessListPath)
Dim strClientAccessList As String = readCLientTxtListReader.ReadToEnd
Console.Write(strClientAccessList)
readCLientTxtListReader.Close()
Dim i As Integer
Dim aryClientAccessList() As String
aryClientAccessList = strClientAccessList.Split(vbTab)
For i = 0 To UBound(aryClientAccessList)
Console.WriteLine(aryClientAccessList)
Next i
The problem about this is that it just creates a new instance of the array as each individual string of characters between each vbtab. which means, the arrays look like:
ID
Name
URL
1
client1
client1.com
2
client2
client2.com
3
client3
client3.com
Which is not really what I need.
Any ideas?
If you need more info, let me know.
Edit: As an added side-note, I believe multidimensional arrays are what I am looking for, and am currently looking them up now, but if you have any more information on these, I would greatly appreciate it.
The way I am reading your end goal is that you want to have an array that that contains each row of the file and that each row should be an array with the tokens for that row in it. If that is correct, then you could do something like this:
var lines = new List<string[]>();
using (var strReplicationDataClientAccessListPath = new FileStream("path", FileMode.Open))
using (var streamReader = new StreamReader(strReplicationDataClientAccessListPath))
{
while (streamReader.Peek() >= 0)
{
var line = streamReader.ReadLine();
if (!string.IsNullOrEmpty(line))
lines.Add(line.Split('\t'));
}
}
foreach (var line in lines)
{
foreach (var token in line)
Console.Write(token);
Console.WriteLine();
}
I have not done VB in a long time but here is the C# which can be run through a converter to get VB.NET. Also I did it using a List, if you need an array at the end you can do:
lines.ToArray();
This is rclements code
converted to VB
Dim lines = New List(Of String())()
Using strReplicationDataClientAccessListPath = New FileStream("path", FileMode.Open)
Using streamReader = New StreamReader(strReplicationDataClientAccessListPath)
While streamReader.Peek() >= 0
Dim line = streamReader.ReadLine()
If Not String.IsNullOrEmpty(line) Then
lines.Add(line.Split(ControlChars.Tab))
End If
End While
End Using
End Using
For Each line As var In lines
For Each token As var In line
Console.Write(token)
Next
Console.WriteLine()
Next
You are trying to simulate CSV -> DataTable workflow, where vbTab is your CSV delimiter, and DataTable is your storage structure (you can query by field name, and by row index). There are numerous solutions on the internet, just google for CSV to DataTable.
Here is one, linked from here (SO answer).
If you still want multi-dimensional arrays, I recommended a List(Of String()) instead of String(,), because you would then not need to manage memory allocation. Each line of data would be an element of List, and a single dimension array, where column values are array elements 0-N.
To read from file, you can use IO.File.ReadAllLines.
Is it what you need?
'Read Values from the text file and store in a DataTable
Dim dt As New DataTable
Using TextReader As New IO.StreamReader("C:\Data.txt")
Dim Line As String = TextReader.ReadLine
If String.IsNullOrEmpty(Line) Then
MsgBox("No Data")
Exit Sub
End If
With Line.Split(vbTab)
dt.Columns.Add(.GetValue(0))
dt.Columns.Add(.GetValue(1))
dt.Columns.Add(.GetValue(2))
End With
Do
Line = TextReader.ReadLine
If Line Is Nothing Then Exit Do
dt.Rows.Add(Line.Split(vbTab))
Loop
End Using
'Print the DataTable header
For Each Column As DataColumn In dt.Columns
Console.Write(Column.ColumnName & vbTab)
Next
Console.WriteLine(vbCrLf & New String("-", 24))
'Print the DataTable contents
For Each Row As DataRow In dt.Rows
Console.WriteLine(Row("ID") & vbTab & Row("Name") & vbTab & Row("URL"))
Next
I have added another solution using List in case you prefer it more than the DataTable:
'Read Values from the text file and store in a List of type Tuples
Dim Values As New List(Of Tuple(Of String, String, String))
Using TextReader As New IO.StreamReader("C:\Data.txt")
Dim Line As String = TextReader.ReadLine
Do Until Line Is Nothing
With Line.Split(vbTab)
Values.Add(Tuple.Create(.GetValue(0).ToString, .GetValue(1).ToString, .GetValue(2).ToString))
End With
Line = TextReader.ReadLine
Loop
End Using
'Print the List contents
For Each T As Tuple(Of String, String, String) In Values
Console.WriteLine(T.Item1 & vbTab & T.Item2 & vbTab & T.Item3)
Next
I am trying to select string values from an Access database and then place them into an array of strings so that I can perform a loop statement on the array.
However I don't know how to place the result of the query into an array. I know how to query the database but all I need is how to put the result in an array.
My select statement is Select motonum from moto. I want to put motonum in an array.
The whole code to read the data is:
connect2()
If Not cnn2.State = ConnectionState.Open Then
'open connection
cnn2.Open()
'MessageBox.Show("chk2")
End If
cmd5.Connection = cnn2
cmd5.CommandText = "Select motonum from moto"
myData5 = cmd5.ExecuteReader
While myData5.Read
'code to return results here
End While`
There are any number of different ways to approach this, depending on the actual needs of your project. First and foremost, I would ask if you actually require a string array as the return type. For most cases, an array is less useful that a List(Of String) or other types which implement IEnumerable.
Here are two options, both of which involve a List(Of String). However, one returns the List to the caller, which can then choose to employ the many useful methods of the List type in working with the data:
THIS is the way I would recommend:
Public Function getListOfMotonum() As List(Of String)
Dim SQL As String = "SELECT motonum FROM moto"
Dim output As New List(Of String)()
' Set the connection string in the Solutions Explorer/Properties/Settings object (double-click)
Using cn = New SqlConnection(Properties.Settings.[Default].MyConnectionString)
Using cmd = New SqlCommand(SQL, cn)
cn.Open()
Try
Dim dr = cmd.ExecuteReader()
While dr.Read()
output.Add(dr("motonum").ToString())
End While
Catch e As SqlException
' Do some logging or something.
MessageBox.Show("There was an error accessing your data. DETAIL: " & e.ToString())
End Try
End Using
End Using
Return output
End Function
Here is a trivial example of code which consumes the output of this function:
Private Sub PrintListToConsole()
Dim MyMotonumList = Me.getListOfMotonum()
For Each item As String In MyMotonumList
Console.WriteLine(item)
Next
End Sub
If your project REQUIRES a string array, the approach may vary. You can return a string from the same function with a couple minor modifications:
' Change the return type in the function signature:
Public Function getArrayOfMotonum() As String()
Dim SQL As String = "SELECT motonum FROM moto"
Dim output As New List(Of String)()
' . . . Same Data Access code as above:
' Just use the .ToArray method of the List class HERE:
Return output.ToArray()
End Function
Or, you can use the same method in your client code, consuming the original function which returns a list:
Private Sub PrintArrayToConsole()
Dim MyMotonumArray = Me.getArrayOfMotonum()
For Each item As String In MyMotonumArray
Console.WriteLine(item)
Next
End Sub
Returning the List from your function provides a more flexible return type, with many useful methods.
As a side note, allow me to recommend the Using block when consuming data access resources. This handles the proper tear down and disposal of the Connection and Command objects for you.