How to build up this list and randomize it? - vb.net

I am making a quiz for my computer science class and the basic concept is that you have 15 keywords and 15 definitions. All need to be randomly displayed and the correct answer has to appear. The user has to match the correct definition to the keyword twice and then that keyword and definition are not displayed again. When all have been answered twice the quiz is over.
I have stored both my keywords and my definitions in the same file so they don't get out of sync. The text file looks like so:
Keyword1 = Definition1
Keyword2 = Definition2
Keyword3 = Definition3
etc (Total of 15)
My main form looks like this:
Public Class quiz
Private Sub quiz_load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles myBase.Load
Dim MyList As List(Of KeyValuePair(Of String, String)) = New List(Of String, String))
For Each line As String In System.IO.File.ReadAllLines("my-file-path")
Dim Pair() As String = line.split("=")
mylist.add(New KeyValuePair(Of String, String)(Pair(0), Pair(1)))
Next
I am displaying the random keyword in a label and the definitions in radiobuttons. Two need to be random definitions and one has to be the correct definition to the keyword shown, which also needs to be displayed randomly.
What I am asking is:
How do I finish this list off as it is overwriting the other 15 lines only using the last one?
How can I randomize the list of keywords and definitions for when they are displayed?
How can I remove the items when each keyword has been matched to its definition twice? E.G: Keyword 1 and definition 1 have been answered correctly twice so remove from list so it won't be displayed again.

This should give you an idea:
Const NUMBER_OF_ANSWERS As Integer = 3
Dim kv As New Dictionary(Of String, String)
kv.Add("Keyword1", "Definition1")
kv.Add("Keyword2", "Definition2")
kv.Add("Keyword3", "Definition3")
Dim r As New Random
Dim kvRandom As List(Of KeyValuePair(Of String, String)) =
kv.OrderBy(Function() r.Next).ToList
'questions will appear in random order
For Each line As KeyValuePair(Of String, String) In kvRandom
Dim keyword As String = line.Key
Dim correctDefinition As String = line.Value
Dim keywords As New List(Of String)
keywords.Add(keyword)
keywords.AddRange(kv.Keys.Except({keyword}).
OrderBy(Function() r.Next).Take(NUMBER_OF_ANSWERS - 1))
Dim definitionsRandom As List(Of String) =
keywords.Select(Function(x) kv(x)).OrderBy(Function() r.Next).ToList
'TODO: need to write some code here
'display keyword and three possible definitions to the user
'(out of which one is correct)
'answers will also appear in random order
'Check answer against value stored in "correctDefinition"
Next
The code is pretty much self-explanatory, if you have any questions, please let me know in comments.
EDIT: Here is how you can populate your dictionary from a file.
'assuming file structure is like this:
'keyword1,definition1
'keyword2,definition2
'keyword3,definition3
'...
For Each line As String In IO.File.ReadAllLines("keywords_and_definitions.txt")
Dim parts() As String = line.Split(",")
kv.Add(parts(0), parts(1))
Next

After you figure out your loading issues, you can follow this basic algorithm to do the rest of your tasks. I don't want to give you exact code for a class assignment. Figuring that kind of thing out is half the fun of learning programming.
Loop through each of the questions, keeping an index to the current
question.
Declare a new list of answers and place the correct answer
from the current question in to the list.
Pick 3 more answers
randomly that are NOT the correct answer, and answers than have been
picked for this question and add them to the answer list.
Randomize the answer list.
Display the questions and answers
Check the chosen answer against the answer for the current question.
Repeat for every question.

Related

extract list of string from list of custom class

i have a list(of custom class)
and i want to extract a list of all 'name' String, from it, through linq
I know how to do with a loop, but i need to get it with a linear, brief linq instruction.
i've checked this help
C# Extract list of fields from list of class
but i have problem in linq correct syntax
in particular because i would like to extract a New List(Of String)
Class Student
Sub New(ByVal NewName As String, ByVal NewAge As Integer)
Name = NewName
Age = NewAge
End Sub
Public Name As String
Public Age As Integer
End Class
Public Sub Main
Dim ClassRoom as New List(Of Student) From {New Student("Foo",33), New Student("Foo2",33), New Student("Foo3",22)}
Dim OneStudent as Student = ClassRoom(0)
Dim AllStudentsNames As New List(Of String) From {ClassRoom.Select(Function(x) x.Name <> OneStudent.Name).ToList}
End Sub
But something wrong...
Any help?
P.S. Since c# it's close to vb.Net, also c# helps are well welcome.
First, you don't need to create a new list From the one returned by the LINQ method. It's already in a new list at that point, so you can just set AllStudentsNames equal directly to what the ToList method returns.
Second, you are not selecting the name. You are selecting the result of the equality test to see if the names are different. In other words, when you say Select(Function(x) x.Name <> OneStudent.Name), that returns a list of booleans, where they true if the names are different and false if the names are the same. That's not what you want. You want the list of names, so you need to select the name.
Third, if you need to filter the list so that it only returns ones where the name is different, then you need to add a call to the Where method.
Dim AllStudentsNames As List(Of String) = ClassRoom.
Where(Function(x) x.Name <> OneStudent.Name).
Select(Function(x) x.Name).
ToList()

VB.NET copy a 2-dimenion List into a one dimension list

In my original code I have a list object containing 2 columns, Word and Percent. I sort the list but only want to return the list containing just the Word
Here is some example code broken down into something simple:
Public Function SortMyWords() as list(of string)
Dim Words As WordsToSort
Dim ListofWords As New List(Of WordsToSort)
Words.Word = "John"
Words.Percent = "10"
ListofWords.Add(Words)
Words.Word = "Robert"
Words.Percent = "1"
ListofWords.Add(Words)
ListofWords = ListofWords.OrderBy(Function(x) x.Percent).ToList()
End Sub
Public Structure WordsToSort
Public Word As String
Public Percent As String
Public Sub New(ByVal _word As String, ByVal _percent As String)
Word = _word
Percent = _percent
End Sub
End Structure
At the end of the SortMyWords function, I want to return just the Word column back as a list, I'm not sure if I can do this direct - i.e.
Return Listofwords(column Word) or whether I need to copy my ListofWords into a new list, just containing the Column Word - something like this (which doesn't work)
Dim Newlist As New List(Of String)
Newlist.AddRange(ListofWords(Words.Word))
Return NewList
Any suggestions on whether I should do this completely differently (and better) would be really appreciated as I am trying to get my head around objects and although I use them all the time, I'm new to structures and list objects.
Thanks for any help, this has been driving me crazy for an hour now.
I think you're close. Try:
ListOfWords
.OrderBy(Function(x) x.Percent)
.Select(Function(x) x.Word)
.ToList()
If you prefer, you can also use the LINQ syntax:
(from w in ListOfWords
orderby w.Percent ascending
select w.Word).ToList()
Note that the return type is a List(Of String) and not a List(Of WordsToSort) anymore. So you cannot assign it back to the variable ListOfWords again like you do in your sample code.

How can I populate this dictionary from a textfile?

I am making a quiz for my computer science class and the basic concept is that you have 15 keywords and 15 definitions. All need to be randomly displayed and the correct answer has to appear. The user has to match the correct definition to the keyword twice and then that keyword and definition are not displayed again. When all have been answered twice the quiz is over.
I have stored both my keywords and my definitions in the same file so they don't get out of sync. The text file looks like so:
Keyword1,Definition1
Keyword2,Definition2
Keyword3,Definition3
Keyword4,Definition4
etc (15 lines in total)
Currently I have my dictionary manually created like so:
Const NUMBER_OF_ANSWERS As Integer = 3
Public Class Form1
Dim kv As New Dictionary(Of String, String)
kv.Add("Keyword1", "Definition1")
kv.Add("Keyword2", "Definition2")
kv.Add("Keyword3", "Definition3")
kv.Add("Keyword4", "Definition4")
kv.Add("Keyword5", "Definition5")
kv.Add("Keyword6", "Definition6")
kv.Add("Keyword7", "Definition7")
kv.Add("Keyword8", "Definition8")
kv.Add("Keyword9", "Definition9")
kv.Add("Keyword10", "Definition10")
kv.Add("Keyword11", "Definition11")
kv.Add("Keyword12", "Definition12")
kv.Add("Keyword13", "Definition13")
kv.Add("Keyword14", "Definition14")
kv.Add("Keyword15", "Definition15")
Dim r As New Random
Dim kvRandom As List(Of KeyValuePair(Of String, String)) =
kv.OrderBy(Function() r.Next).ToList
'questions will appear in random order
For Each line As KeyValuePair(Of String, String) In kvRandom
Dim keyword As String = line.Key
Dim correctDefinition As String = line.Value
Dim keywords As New List(Of String)
keywords.Add(keyword)
keywords.AddRange(kv.Keys.Except({keyword}).
OrderBy(Function() r.Next).Take(NUMBER_OF_ANSWERS - 1))
Dim definitionsRandom As List(Of String) =
keywords.Select(Function(x) kv(x)).OrderBy(Function() r.Next).ToList
'TODO: need to write some code here
'display keyword and three possible definitions to the user
'(out of which one is correct)
'answers will also appear in random order
'Check answer against value stored in "correctDefinition"
LabelKeyword.Text = keyword
RadioButtonDef1.Text = definitionsRandom(0)
RadioButtonDef2.Text = definitionsRandom(1)
RadioButtonDef3.Text = definitionsRandom(2)
Next
End Sub
I know that to populate a dictionary from a textfile I do the following:
For Each line As String In IO.File.ReadAllLines("keywords_and_definitions.txt")
Dim parts() As String = line.Split(",")
kv.Add(parts(0), parts(1))
Next
However I am not sure how to change this code to successfully implement this. Thanks to previous help here I was told to do this (by #Neolisk):
set your progress variable to 0 of 14 (number of questions minus 1, indexes are zero based in VB.NET). At first question, display question #0, when user presses Next, increment progress variable. Don't forget to count valid/invalid answers. You may want to store full answer history for a user. If you need mode detail on this one, I think it's worth asking a separate question - provide the functionality you need there.
Again I am not sure how to go about doing this. The above code works wonders it's just I'm not sure how to change the code to populate the dictionary from the text file rather than how I have done it above as it is a requirement that we include our keywords and definitions from a text file.
Maybe I'm not understanding your question, but just mixing the two together should do the trick, no??
Const NUMBER_OF_ANSWERS As Integer = 3
Public Class Form1
Dim kv As New Dictionary(Of String, String)
For Each line As String In IO.File.ReadAllLines("keywords_and_definitions.txt")
Dim parts() As String = line.Split(",")
kv.Add(parts(0), parts(1))
Next
Dim r As New Random
...
Or am I not understanding your question?
Also, I'll give you the hint, since this is homework, that the Dim parts() As String could be moved outside of your loop.
Hopw this is what you were asking and it helps set you in the right direction

Why won't the correct definition in my code work in an "If/Else" statement?

I am making a quiz for my computer science class and the basic concept is that you have 15 keywords and 15 definitions. All need to be randomly displayed and the correct answer has to appear. The user has to match the correct definition to the keyword twice and then that keyword and definition are not displayed again. When all have been answered twice the quiz is over.
I have stored both my keywords and my definitions in the same file so they don't get out of sync. The text file looks like so:
Keyword1,Definition1
Keyword2,Definition2
Keyword3,Definition3
...
Thanks to the help from others here on StackOverflow I have managed to get the randomizing and dictionary completed. For reference that looks like this:
Public Class Form1
Private kv As Dictionary(Of String, Answer) 'Define kv as a dictionary
Private keyword As String
Private correctDefinition As String
Const NUMBER_OF_ANSWERS As Integer = 3 'Define the constant NUMBER_OF_ANSWERS
Private Sub RandomiseAnswers()
Dim r As New Random
Dim kvRandom As List(Of KeyValuePair(Of String, Answer)) =
kv.OrderBy(Function() r.Next).ToList
'questions will appear in random order
For Each line As KeyValuePair(Of String, Answer) In kvRandom
Dim keyword As String = line.Key
Dim correctDefinition As String = line.Value.Answer
Dim keywords As New List(Of String)
keywords.Add(keyword)
keywords.AddRange(kv.Keys.Except({keyword}).
OrderBy(Function() r.Next).Take(NUMBER_OF_ANSWERS - 1))
Dim definitionsRandom As List(Of String) =
keywords.Select(Function(x) kv(x).Answer).OrderBy(Function() r.Next).ToList
LabelKeyword.Text = keyword
RadioButtonDef1.Text = definitionsRandom(0)
RadioButtonDef2.Text = definitionsRandom(1)
RadioButtonDef3.Text = definitionsRandom(2)
Next
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'The text file is structured like so:
'Keyword1,Definition1
'Keyword2,Definition2
'Keyword3,Defintion3
'...
'This makes sure that the keywords and the definitions do not get out of sync when randomising, as a dictionary is a key-value data structure. Call the key, get the right value etc.
kv = New Dictionary(Of String, Answer) 'kv = a new dictionary
For Each line As String In IO.File.ReadAllLines("C:\Users\Matt\Documents\keywords.txt") 'Foreach loop populating the dictionary from the text file
Dim parts() As String = line.Split(",") 'Split the Keywords from the definitions where the , is
kv.Add(parts(0), New Answer With {.Answer = parts(1), .Answered = False}) 'Add the two parts (Keyword and Definition) to the Parts with the Answer class
Next
Dim r As New Random 'Define r as new random
Dim kvRandom As List(Of KeyValuePair(Of String, String)) =
kv.OrderBy(Function() r.Next) _
.Select(Function(x) New KeyValuePair(Of String, String)(x.Key, x.Value.Answer)) _
.ToList() 'A Select method to convert the items in the list properly
'questions will appear in random order
For Each line As KeyValuePair(Of String, String) In kvRandom
Dim keyword As String = line.Key
Dim correctDefinition As String = line.Value 'Checks that the correct definition will be displayed when its keyword is randomly displayed.
'Define keywords as a new list
Dim keywords As New List(Of String)
keywords.Add(keyword) 'Adds the keyword to the list as the Part(0) from the text file in the first loop
keywords.AddRange(kv.Keys.Except({keyword}).
OrderBy(Function() r.Next).Take(NUMBER_OF_ANSWERS - 1))
Dim definitionsRandom As List(Of String) =
keywords.Select(Function(x) kv(x).Answer).OrderBy(Function() r.Next).ToList 'Define definitionsRandom as a list. Checks against correctDefinition to know to always display the correct answer as one of the
'random definitions
LabelKeyword.Text = keyword 'Randomly display a keyword
RadioButtonDef1.Text = definitionsRandom(0) 'Randomly display a definition. Checks against correctDefinition to see make sure one definition is always the right answer.
RadioButtonDef2.Text = definitionsRandom(1) 'Randomly display a definition. Checks against correctDefinition to see make sure one definition is always the right answer.
RadioButtonDef3.Text = definitionsRandom(2) 'Randomly display a definition. Checks against correctDefinition to see make sure one definition is always the right answer.
Next
End Sub
Private Sub ButtonNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonNext.Click
'If (RadioButtonDef1.Checked And RadioButtonDef1.Text = correctDefinition) Or (RadioButtonDef2.Checked And RadioButtonDef2.Text = correctDefinition) Or (RadioButtonDef3.Checked And RadioButtonDef3.Text = correctDefinition) Then
' If kv(keyword).Answered Then
' kv.Remove(keyword)
' Else
' kv(keyword).Answered = True
' End If
'Else
' MsgBox("Incorrect Answer!")
'End If
If (RadioButtonDef1.Checked And RadioButtonDef1.Text = correctDefinition) Or (RadioButtonDef2.Checked And RadioButtonDef2.Text = correctDefinition) Or (RadioButtonDef3.Checked And RadioButtonDef3.Text = correctDefinition) Then
MsgBox("Correct Answer")
Else
MsgBox("Incorrect Answer. The correct answer is: " & correctDefinition)
End If
End Sub
End Class
I use a subroutine in my buttonNext_click to prevent duplicate code, as you can see above Private Sub RandomiseAnswers().
my issue however is when I come down to the If/else statement where I determine whether the user has selected the correct answer. As you can see I have commented out the original line as I found that it didn't work, and therefore I created one which would display a message box. By using that If/Else statement I have found that it always displays the Incorrect Answer message box and it doesn't display the correct definition.
What is puzzling me the most is that I know that correctDefinition works as it will always display the correct definition to the current keyword however I cannot seem to fathom out how to make it work in the conditional/s.
Does anyone have a possible solution as to why it doesn't seem to like being used in the If/Else statement/s but does work when randomising.
Sorry if it is hard to understand what I am asking.
Any help is much appreciated.
EDITS
code relevant to the Answer class
Public Class Answer
Public Answer As String
Public Answered As Boolean
End Class
You declare correctDefinition twice in your code. Declare it once or better yet make correctDefinition an array eg.
Private correctDefinition() String = New String() { "Definition 1", "Definition 2", "Definition 3" }

VB: List(Of List(Of String)) keeps changing the content of the outer list when I change the inner one?

I'm writing a program in VB, and I need to make a list of lists (I've already figured out how to do that one). The problem is, the outer list is going to need a different number of elements depending on other variables elsewhere in the program.
I've looped this code:
Dim rep As Long = 1023
Dim items As List(Of String)
items.Add("First Entry")
items.Add("Second Entry")
items.Add("Third Entry")
items.Add("Fourth Entry")
'(sake of argument, these are the variables
'that will be changing vastly earlier
'in the program, I put them in this way to simplify
'this part of my code and still have it work)
Dim myList As New List(Of List(Of String))
Dim tempList As New List(Of String)
For index = 1 To Len(rep.ToString)
tempList.Add(items(CInt(Mid(rep.ToString, index, 1))))
Next
myList.Add(tempList)
tempList.Clear()
My issue is with that last part; every time I add the tempList to myList, it's fine, but when I clear tempList, it also clears the version of tempList in myList.
myList will have a count of 1, but the list inside it has a count of 0 as soon as I clear tempList. And I have to clear tempList because I'm looping this section of code over and over, a variable number of times.
Is there a way around this? Am I being a horrible noob?
You're using the same tempList each time, instead of making a new one.
You likely need to do:
myList.Add(tempList)
tempList = new List(Of String) ' Create a new List(Of T), don't reuse...