Reading random line of XML file in Visual Studio 2010 - vb.net

I'm just starting out on one of my first programming projects in visual studio 2010.
I have an XML file that I have added into the program as an item. It has the following structure:
<lexeme><grapheme>Aalesund</grapheme> <phoneme>'A:lI2s,Vnd</phoneme></lexeme>
There are 400,000 entries like that and what I would like to do is on a button press have a random lexeme selected from the xml file and then two labels populated with the corresponding grapheme and phoneme.
Could anyone point me in the right direction to begin with please? The tutorials I have found are for loading specific amounts of data, not just one random line and reference an external xml file location, not one that is internal to the project.
Thanks in advance.
Edit: I should say that I mean pseudo-random number. I was hoping to find a rand() function, but can't seem to?

There isn't a direct way of getting a random line from an XML. And relying on line number is dangerous because if the format of the XML were to be changed from:
<lexeme><grapheme>Aalesund</grapheme> <phoneme>'A:lI2s,Vnd</phoneme></lexeme>
to:
<lexeme>
<grapheme>Aalesund</grapheme>
<phoneme>'A:lI2s,Vnd</phoneme>
</lexeme>
Your randomly generated line number might not line up with a <lexeme> element anymore.
I think the best way to do it is to get all of the <lexeme> elements in a list and randomly generate a number that is within the range of the list:
(forgive me, but the code sample is in c#, I don't trust my VB.Net enough to write my code in VB)
var lexemeList = xDocument.Descendants("lexeme").ToList();
var random = new Random();
var randomLexeme = lexemeList[random.Next(0, lexemeList.Count-1)];
randomLexme will then have a pseudo-random <lexeme> element and you can parse it as you need to get the appropriate <grapheme> and <phoneme> elements.
If you do this though, keep in mind that the .net Random class is pseudo-random and uses the current timestamp as a seed. If you are going to be accessing objects regularly, it would be advisable to make the var random = new Random() variable as class-level field and create it once and just used the Next() method to get the next number, rather than creating a new Random() object whenever you need a random number.
Here's a more self contained function in VB.Net:
Dim rand = New Random()
Dim myXml = New XDocument()
Function GetRandomLexeme() as XElement
Dim lexemeList = myXml.Descendants("lexeme").ToList()
Dim randomLexeme = lexemeList(rand .Next(0, lexemeList.Count - 1))
GetRandomLexeme = randomLexeme
End Function

Related

Match Words and Add Quantities vb.net

I am trying to program a way to read a text file and match all the values and their quantites. For example if the text file is like this:
Bread-10 Flour-2 Orange-2 Bread-3
I want to create a list with the total quantity of all the common words. I began my code, but I am having trouble understanding to to sum the values. I'm not asking for anyone to write the code for me but I am having trouble finding resources. I have the following code:
Dim query = From data In IO.File.ReadAllLines("C:\User\Desktop\doc.txt")
Let name As String = data.Split("-")(0)
Let quantity As Integer = CInt(data.Split("-")(1))
Let sum As Integer = 0
For i As Integer = 0 To query.Count - 1
For j As Integer = i To
Next
Thanks
Ok, lets break this down. And I not seen the LET command used for a long time (back in the GWBASIC days!).
But, that's ok.
So, first up, we going to assume your text file is like this:
Bread-10
Flour-2
Orange-2
Bread-3
As opposed to this:
Bread-10 Flour-2 Orange-2 Bread-3
Now, we could read one line, and then process the information. Or we can read all lines of text, and THEN process the data. If the file is not huge (say a few 100 lines), then performance is not much of a issue, so lets just read in the whole file in one shot (and your code also had this idea).
Your start code is good. So, lets keep it (well ok, very close).
A few things:
We don't need the LET for assignment. While older BASIC languages had this, and vb.net still supports this? We don't need it. (but you will see examples of that still floating around in vb.net - especially for what we call "class" module code, or "custom classes". But again lets just leave that for another day.
Now the next part? We could start building up a array, look for the existing value, and then add it. However, this would require a few extra arrays, and a few extra loops.
However, in .net land, we have a cool thing called a dictionary.
And that's just a fancy term of for a collection VERY much like an array, but it has some extra "fancy" features. The fancy feature is that it allows one to put into the handly list things by a "key" name, and then pull that "value" out by the key.
This saves us a good number of extra looping type of code.
And it also means we don't need a array for the results.
This key system is ALSO very fast (behind the scene it uses some cool concepts - hash coding).
So, our code to do this would look like this:
Note I could have saved a few lines here or there - but that would make this code hard to read.
Given that you look to have Fortran, or older BASIC language experience, then lets try to keep the code style somewhat similar. it is stunning that vb.net seems to consume even 40 year old GWBASIC type of syntax here.
Do note that arrays() in vb.net do have some fancy "find" options, but the dictionary structure is even nicer. It also means we can often traverse the results with out say needing a for i = 1 to end of array, and having to pull out values that way.
We can use for each.
So this would work:
Dim MyData() As String ' an array() of strings - one line per array
MyData = File.ReadAllLines("c:\test5\doc.txt") ' read each line to array()
Dim colSums As New Dictionary(Of String, Integer) ' to hold our values and sum them
Dim sKey As String
Dim sValue As Integer
For Each strLine As String In MyData
sKey = Split(strLine, "-")(0)
sValue = Split(strLine, "-")(1)
If colSums.ContainsKey(sKey) Then
colSums(sKey) = colSums(sKey) + sValue
Else
colSums.Add(sKey, sValue)
End If
Next
' display results
Dim KeyPair As KeyValuePair(Of String, Integer)
For Each KeyPair In colSums
Debug.Print(KeyPair.Key & " = " & KeyPair.Value)
Next
The above results in this output in the debug window:
Bread = 13
Flour = 2
Orange = 2
I was tempted here to write this code using just pure array() in vb.net, as that would give you a good idea of the "older" types of coding and syntax we could use here, and a approach that harks all the way back to those older PC basic systems.
While the dictionary feature is more advanced, it is worth the learning curve here, and it makes this problem a lot easier. I mean, if this was for a longer list? Then I would start to consider introduction of some kind of data base system.
However, without some data system, then the dictionary feature is a welcome approach due to that "key" value lookup ability, and not having to loop. It also a very high speed system, so the result is not much looping code, and better yet we write less code.

Getting a count of "find" from multiple .txt files

I am currently running a find and replace through hundreds of .txt files at a time. I am looking for a way to pull a count of the number of finds for my value.
Here is the code I am currently running, hoping to be able to add to or modify this code.
Dim flatfiles As String() = IO.Directory.GetFiles("C:\DATA\TEST\", "*.txt").Where(Function(x) File.ReadAllText(x).Contains("Bob")).ToArray
For Each f As String In flatfiles
Dim contents As String = File.ReadAllText(f)
File.WriteAllText(f, contents.Replace("Bob", "Bill"))
Next
One (inefficient) way to do this would be to include a counter outside of the For Each loop (Dim itemsFound as Integer = 0), then increment it by the count of find in each file, using something like:
itemsFound = itemsFound + (Regex.Split(contents, find).Length - 1)
Regex.Split splits the string up whenever it finds find, which means the count you're looking for is one less than the number of items in the list.
I would say as well, that you're calling File.ReadAllText twice in your code, so you could improve it by getting rid of the Where code, and just check in your For each loop (seeing as you're now counting the number of instances in the file anyway, it's easy enough to check for 0 occurrences). Alternatively, you could replace the .Where code to store the contents of the file in an array rather than the name of the files (although this can be dangerous if the files are large); or you could even just do it all in Linq if you want some obfuscated code...

Read data from JSON file, add new data following data structure VB.NET

Okay, So I have been trying to wrap my small head around this topic for some time now. All I want to do is:
1) Read all data from a .json file
2) Add data to the json file, while still following structure (Adding objects withing java somehow maybe?)
3) Save file back
I have figured out how to download json.net and add it to my project. I just have no clue how to use it.
I am a big noob at java and vb, so please don't reply with a bunch of unnecessary stuff that won't help. (Really irritated by this already :|)
I am writing this with a GUI, so no console stuff, as I seen from most of the sources on the interweb.
Things I have tried: Reading all lines and storing into var, array and or string.
Dim str() As String = IO.File.ReadAllLines("C:\MCHCI_Profile.txt")
I got this from somewhere but threw and error of 1 dimensional array
Dim singleChar As Char
singleChar = str.Chars(14)
Somethings with streamreader and writer but not too much, as it confuses me.
Using sr As StreamReader = New StreamReader("C:\MCHCI_Profile.txt")
Do
ListBox1.Items.Add(sr.ReadLine())
Loop Until sr.EndOfStream
End Using
^This seemed to work, it added all the right data into combobox and kept json structure, but I don't know what to do with it.
Final conclusion
It seems like the only real way to do this is with json.net
So please let me know how to read data, add simple objects to it and save it back
Thank you !!!
As of now i don't get what actually you are trying to achieve. Let me assume that
1. You are accepting a text file content to a one dimensional array.
2. then you are selecting a single character from particular index from that array, isn't it?
this will achieve the first option without fail.
Dim str() As String = File.ReadAllLines("D:\sample.txt")
if you want particular line of text then you can take it from the array by using the index value as like the following:
Dim lineOfText As String = str(14)
if you want a single character from particular line of text then you can take it from the array by using the index value as like the following:
Dim singleChar As Char=str(14).ToCharArray()(2)

After using dictonary to link keywords to definitions in a quiz how to make it always display a corrcet answer

For a quiz I used the dictionary to link the keywords to the correct definition. The main issue im facing is how would I make it so that when a keyword is displayed that out of three definitions that one is correct in a random order each time out of a possibility of three. shown below is my code of how i did my dictionary with my definitions of how i randomised them. Its abit long winded but makes it easier for me to read :P I am a student and not the best at visual basic.
In a module i have the following code
Public Keywords As String() = IO.File.ReadAllLines("Keywords File Path")
Public Answers As String() = IO.File.ReadAllLines("Definitions File Path")
After this i have a main form that contains the dictionary and how i have added them and done the random for the keywords and definitions.
This is under main form
Public Link As New Dictionary(Of String, String)
Dim Rand As New Random
Dim KeyIndex As Integer = Rand.Next(0, 14)
Dim KeywordRand As String = Keywords(KeyIndex)
The random I repeated for the 3 answers for each Definition label
Under Main Form load i put the following
Link.add(Keywords(0), Answers(0))
Link.add(Keywords(1), Answers(1))
this continued for other keywords and defintions
Definition1.text = "a) " & AnswerRand1
this also repeated for the other 2 definitions
now the problem is that I want to show the definitions by them selfs. None can be the same.
Also the main issue is that I want it to show the correct definition always and it to be as one of the three definitions as a random chosen label as such.

How can I read individual lines of a CSV file into a string array, to then be selectively displayed via combobox input?

I need your help, guys! :|
I've got myself a CSV file with the following contents:
1,The Compact,1.8GHz,1024MB,160GB,440
2,The Medium,2.4GHz,1024MB,180GB,500
3,The Workhorse,2.4GHz,2048MB,220GB,650
It's a list of computer systems, basically, that the user can purchase.
I need to read this file, line-by-line, into an array. Let's call this array csvline().
The first line of the text file would stored in csvline(0). Line two would be stored in csvline(1). And so on. (I've started with zero because that's where VB starts its arrays). A drop-down list would then enable the user to select 1, 2 or 3 (or however many lines/systems are stored in the file). Upon selecting a number - say, 1 - csvline(0) would be displayed inside a textbox (textbox1, let's say). If 2 was selected, csvline(1) would be displayed, and so on.
It's not the formatting I need help with, though; that's the easy part. I just need someone to help teach me how to read a CSV file line-by-line, putting each line into a string array - csvlines(count) - then increment count by one so that the next line is read into another slot.
So far, I've been able to paste the numbers of each system into an combobox:
Using csvfileparser As New Microsoft.VisualBasic.FileIO.TextFieldParser _
("F:\folder\programname\programname\bin\Debug\systems.csv")
Dim csvalue As String()
csvfileparser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
csvfileparser.Delimiters = New String() {","}
While Not csvfileparser.EndOfData
csvalue = csvfileparser.ReadFields()
combobox1.Items.Add(String.Format("{1}{0}", _
Environment.NewLine, _
csvalue(0)))
End While
End Using
But this only selects individual values. I need to figure out how selecting one of these numbers in the combobox can trigger textbox1 to be appended with just that line (I can handle the formatting, using the string.format stuff). If I try to do this using csvalue = csvtranslator.ReadLine , I get the following error message:
"Error 1 Value of type 'String' cannot be converted to '1-dimensional array of String'."
If I then put it as an array, ie: csvalue() = csvtranslator.ReadLine , I then get a different error message:
"Error 1 Number of indices is less than the number of dimensions of the indexed array."
What's the knack, guys? I've spent hours trying to figure this out.
Please go easy on me - and keep any responses ultra-simple for my newbie brain - I'm very new to all this programming malarkey and just starting out! :)
Structure systemstructure
Dim number As Byte
Dim name As String
Dim procspeed As String
Dim ram As String
Dim harddrive As String
Dim price As Integer
End Structure
Private Sub csvmanagement()
Dim systemspecs As New systemstructure
Using csvparser As New FileIO.TextFieldParser _
("F:\folder\programname\programname\bin\Debug\systems.csv")
Dim csvalue As String()
csvparser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
csvparser.Delimiters = New String() {","}
csvalue = csvparser.ReadFields()
systemspecs.number = csvalue(0)
systemspecs.name = csvalue(1)
systemspecs.procspeed = csvalue(2)
systemspecs.ram = csvalue(3)
systemspecs.harddrive = csvalue(4)
systemspecs.optical = csvalue(5)
systemspecs.graphics = csvalue(6)
systemspecs.audio = csvalue(7)
systemspecs.monitor = csvalue(8)
systemspecs.software = csvalue(9)
systemspecs.price = csvalue(10)
While Not csvparser.EndOfData
csvalue = csvparser.ReadFields()
systemlist.Items.Add(systemspecs)
End While
End Using
End Sub
Edit:
Thanks for your help guys, I've managed to solve the problem now.
It was merely a matter calling loops at the right point in time.
I would recommend using FileHelpers to do the reading.
The binding shouldn't be an issue after that.
Here is the Quickstart for Delimited Records:
Dim engine As New FileHelperEngine(GetType( Customer))
// To Read Use:
Dim res As Customer() = DirectCast(engine.ReadFile("FileIn.txt"), Customer())
// To Write Use:
engine.WriteFile("FileOut.txt", res)
When you get the file read, put it into a normal class and just bind to the class or use the list of items you have to do custom stuff with the combobox. Basically, get it out of the file and into a real class asap, then things will be easier.
At least take a look at the library. After using it, we use a lot more simple flat files since it is so easy, and we haven't written a file access routine since (for that kinda stuff).
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx
I think your main problem is understanding how arrays work (hence the error message).
You can use split and join functions to convert strings into and out of arrays
dim s() as string = split("1,2,3",",") gives and array of strings with 3 elements
dim ss as string = join(s,",") gives you the string back
Firstly, it's actually really good that you are using the TextFieldParser for reading CSV files - most don't but you won't have to worry about extra commas and quoted text etc...
The Readline method only gives you the raw string, hence the "Error 1 Value of type 'String' cannot be converted to '1-dimensional array of String'."
What you may find easier with combo boxes etc is to use an object (e.g. 'systemspecs') rather than strings. Assign the CSV data to the objects and override the "ToString" method of the 'systemspecs' class to display in the combo box how you want with formatting etc. That way when you handle the SelectedIndexChanged event (or similar) you get the "SelectedItem" from the combo box (which can be Nothing so check) and cast it as the 'systemspecs' to use it. The advantage is that you are not restricted to display the exact data in the combo etc.
' in "systemspecs"...
Public Overrides Function ToString() As String
Return Name ' or whatever...
End Function ' ToString
e.g.
dim item as new systemspecs
item.ID = csvalue(1)
item.Name = csvalue(2)
' etc...
combobox1.Items.Add(item)
Let me know if that makes sense!
PK :-)