Why are all of my Random variables the same (Visual Basic)? - vb.net

I'm trying to use multiple random variables for something I'm making in Visual Studio. This is the code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Declaring random variables
Dim cC1 As New Random
Dim cC2 As New Random
Dim cC3 As New Random
Dim cC4 As New Random
Dim cC5 As New Random
Dim cCard1 As New Integer
cCard1 = cC1.Next(1, 14)
Dim cCard2 As New Integer
cCard2 = cC2.Next(1, 14)
Dim cCard3 As New Integer
cCard3 = cC3.Next(1, 14)
Dim cCard4 As New Integer
cCard4 = cC4.Next(1, 14)
Dim cCard5 As New Integer
cCard5 = cC5.Next(1, 14)
'Computers random choice
Dim x As New Integer
Dim s As New Random
x = s.Next(1, 14)
There's a bit more but it's basically a duplicate. The issue is that these "random" variables are ALL the same. I thought that the error might have been because the code was like so:
Dim cCard1 = cC1.Next(1, 14)
I have written another program which executes what I wanted with the exact same code, while this programs variables aren't all too random. :(
After changing it to the current code, the issue is still prominent and I'm looking for an explanation to why this occurs, and more importantly, a way to correct this error. Any form of help will be highly appreciated!

That is because when you create the Random instance, it uses the current time as its seed. The seed is a number that, when identical, yields the exact same sequence of pseudo-random numbers. In your case this happens fast enough that all instances share the same seed and thus all yield the same first number.
You should create one Random instance and get multiple numbers from it instead.

Related

vb.net - Pick 1000 random files from a folder

I have a folder that has a many files in it. somewhat between 1000 and 15000.
I would need to randomly pick 1000 files from this folder and copy it over to another folder.
I know how to get a single random file from a folder by inserting the list of files in an array and then selecting one randomly, but dont know how to get many while avoiding to select the same file twice.
If for example I have 1001 file in my folder, it will have no trouble getting the fist few, but then towards the end, it is very likely to pick a file that has already been copied over and it would take many tries to find for example the last file just by luck...
my first idea was to divide the number of files by 1000. so for example 1500/1000 = 1.5. and then create a random integer between 0 and 1.5. this would return 1. then do the next rand between nth image and nth image * 1.5.
if the folder hast 15000 files, it would pick the first file randomly between 1 and 15, and then between 6 and 30 and so on..
but there must be a smarter solution for this..
any help appreciated
You can order them randomly:
Dim allFiles = Directory.EnumerateFiles("path")
Dim rnd As New Random()
Dim random1000 = From f In allfiles
Order By rnd.Next()
Select f
Take 1000
Dim list = random1000.ToList()
This is using System.Linq
Using indices into the list of files
Private Shared prng As New Random
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ListOfiles() As String = IO.Directory.GetFiles(BasePath)
Dim indices As IEnumerable(Of Integer)
indices = Enumerable.Range(0, ListOfiles.Length).OrderBy(Function() prng.Next).Take(1000)
For Each idx As Integer In indices
Dim fn As String = ListOfiles(idx)
Stop
Next
End Sub

Visual Basic Randomize() vs New Random

It seems that Randomize() & Rnd() aren't used anymore.
Instead people make something like:
Dim rng as New Random()
Dim randomNo as Integer = rng.Next(10) ' this is a random number between 0 and 10.
Dim anotherRandomNo as Integer = rng.Next(10) ' a different random number.
Could someone tell me why this is considered "better" in most circumstances?
There are a few reasons.
Random has much greater functionality .. Have a look here
Also and more importantly the old Randomize is built into the instantiation of a Random object. By default, Rnd without randomize always started with the same seed number. If you didn't use randomize at the start of your program, each time it ran, it would generate the same sequence of numbers.
Finally, internally the Random object generates numbers in a different way with a better spread of randomness.

Vb Guessing Game Random generator broken

In my code,I have now realised I have to use the New Random function, my code was working before with the Randomize and then the numbers but now it comes up with loads of errors and wont even let me run the program. I think it is only a small error but I just need some help to get the final bit going
Heres the code and thanks for any help :)
I cannot get the code to work with the randomly generated number and I have to use the New Random function I cannot use randomize() Does anybody know how to help here is the code.
Dim timestook As Int32 = 1
Dim usersguess As Integer
Dim value = New Random(0 - 19)
Console.WriteLine("You have to guess this number. It is between 1 and 20. Good Luck !")
usersguess = Console.ReadLine()
'keep looping until they get the right value
While usersguess <> value
'now check how it compares to the random value
If usersguess < value Then
timestook = timestook + 1
Console.WriteLine("You're too low. Go higher ")
ElseIf usersguess > value Then
Console.WriteLine("You're too high. Go Lower.")
timestook = timestook + 1
End If
'If they are wrong the code will run again,after telling the user if they are too high or too low.
usersguess = Console.ReadLine()
End While
' Console.WriteLine("You're correct. Well Done")
If usersguess = value Then
Console.WriteLine("You took,{0}", timestook)
End If
Console.ReadLine()
End Sub
You'll want to do some googling on how to use random numbers. Your problem is that you aren't creating a Random object to handle the random number generation.
Here's how you can fix your code:
Dim randNumGen As New Random() 'Create Random object
Dim value As Integer = randNumGen.Next(0, 20) 'set value equal to a new random number between 0-19
Please note that this code could be further refactored for readability and simplicity (like changing timestook = timestook + 1 to timestook += 1 and selecting better variable names like numberOfGuesses as opposed to timestook, etc.
The expression New Random(0-19) does not do at all what you think it does, name it does NOT return an integer. Instead, it creates an instance of a Random object, which is a type that knows how to create new random values. The 0-19 part of the expression is the seed for the Random object's constructor, and is the same as just passing the value -19.
This looks like it's either homework or personal practice, so I feel like you will be better served in this case with a separate example using the Random type for reference than you would if I fixed the code sample in the question for you:
Dim rnd As New Random()
For i As Integer = 0 To 10
Console.WriteLine(rnd.Next(0, 20))
Next i
It's also worth mentioning here that you typically only want one Random object for your entire program, or at least only one Random object for each logical part of your program. Creating new Random objects resets the seeds, and for best results you want to follow the same seed on subsequent calls to the same instance for a while.

oledbdataadapter command builder getupdate, needs key for argument

I seem to be having an issue. I have a dataset (excel) sourced to a datagridview in a windows forms application. I'm hoping to find a way to refresh/update my dataset within the datagridview after making a change to a cell.
Let me go through the steps I've taken to try and accomplish this. I've added a "refresh" button to the form and I've created a method called write2DGV which will write changes to the dataset after changes are made in the datagridview.
I've added a timer that will allow Excel to update to update the outputs. I've also added code to wipe clean my dataset (which is the datasource for the datagridview). Last I have a retrieve method that will source the dataset to the datagridview via the oledataadapter.
Unfortunately when I run the code I get an error message about not providing a key as an argument to the get update method. I'm not exactly sure what they mean by "key", also the only valid data types for the argument to the get update method is boolean. My code is below:
'Declarations
Dim myDataSet As DataSet
Dim MyCommand As OleDb.OleDbDataAdapter
Dim objWorkSheet As Excel.Worksheet = objExcel.ActiveSheet
Dim sizetimer As New System.Timers.Timer
Sub retrieveMyDataSet()
MyCommand = New OleDbDataAdapter(select * from [MyExcelWorksheet$A13:x150], MyConnection)
myDataSet = New System.Data.DataSet()
MyCommand.Fill(myDataSet)
myDataGridView.DataSource = myDataSet.Tables(0).DefaultView
End Sub
Sub write2Size()
'A-k gets written. Entire graph goes to a-x so I only need to writ the columncount -14
'x is letter 24. k is letter 11. 24-11 = 13. So, offset needs to be -13
'39;Rows 13 through first blank
Dim rowindex As Integer
Dim columnindex As Integer
For rowindex = 1 To myDataGridView.RowCount
For columnindex = 1 To myDataGridView.ColumnCount - 13
objWorkSheet.Cells(rowindex + 13, columnindex + 0) = myDataGridView(columnindex - 1, rowindex - 1).Value
Next
Next
End Sub
Sub refreshDGV()
write2DGV()
myDataSet.Clear()
Dim x As New OleDbDataAdapter("select * from [MyExcelWorksheet$A13:x150]", MyConnection)
Dim oledbCommands As New OleDb.OleDbCommandBuilder(x)
x.UpdateCommand = oledbCommands.GetUpdateCommand() 'oops type! removed = x.UpdateCommand
x.Update(myDataSet)
sizetimer.AutoReset = True
sizetimer.Interval = 2000 '2 seconds
retrieveMyDataSet()
End Sub
Private Sub refreshbtn_Click(sender As System.Object, e As System.EventArgs) Handles refreshbtnSize.Click
refreshDGV()
End Sub
Unfortunately when I run the code I get an error message about not
providing a key as an argument to the get update method.
The reason of this error is explained in this article that you should read carrefully: How To Use ADO.NET to Retrieve and Modify Records in an Excel Workbook With Visual Basic .NET
You are using one of the solution mentionned in this article to update the worksheet, ie Make changes to a DataSet that you have filled with a table/query from an Excel workbook and then call the Update method of the DataAdapter to resolve changes from the DataSet back to the workbook.
But just after we can read:
However, to use the Update method for change resolution you must set
parameterized commands for the DataAdapter's InsertCommand
INSERT INTO [Sheet1$] (F1, F2) values (?, ?)
and UpdateCommand:
UPDATE [Sheet1$]SET F2 = ? WHERE F1 = ?
Parameterized INSERT and UPDATE commands are
required because the OleDbDataAdapter does not supply key/index
information for Excel workbooks; without key/index fields, the
CommandBuilder cannot automatically generate the commands for you.
The message is clear: you have to explicitly write parameterized INSERT and UPDATE commands if you want achieve what you are trying to do.
And don't forget that Excel has a lot a functionnality but is not especially designed to work as a database. So to avoid a lot of problems, I recommand you to switch to another local database (SqlServerCompact, SQlLite, ...).

Same random number generated when run in test Fixture setup

I am trying to generate a random number during testing using NUnit, but it keeps generating the same number. I am using the following function for this purpose.
dim dCount As Integer = Math.Floor((High - Low + 1) * Rnd() + Low)
dim divName As String = "abc" & dCount
Any idea why it is doing this?
Regards,
Sam
Presumably you're executing many tests in quick succession. I don't know exactly what Rnd() does in VB, but it sounds like it's got the typical "new RNG per call" problem.
Create a single instance of Random and use it repeatedly. Note that your maths can be replaced by a simple:
dim dCount as Integer = myRandom.Next(Low, High+1)
One caveat - Random isn't thread-safe. If you need to generate random numbers from different threads, either use locking or thread statics.
On another point: using random numbers will make your unit tests non-deterministic. Are you sure you have to? Sometimes it's appropriate, but not often IME.
Dim dCount As Integer = between(low, high)
Dim divName As String = "abc" & dCount
Dim myRandom As New Random
Private Function between(ByVal low As Integer, ByVal high As Integer) As Integer
between = myRandom.Next(low, high + 1)
End Function