Random string generating same values in different iterations of loop - vb.net

Im making referenceIDs in a function and adding the values to a list.
Dim myListOfItems As New List(Of BasketItem)
Dim refID As String = String.Empty
For Each i In myListOfNames
refID = HelpClass.GenerateRandomString(20)
Dim x As New BasketItem
x.RefID = refID
myListOfItems.Add(x)
Next
The Function looks as follows:
Public Shared Function GenerateRandomString(ByVal length As Integer) As String
Dim chara As Char() = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray()
Dim randomString As String = String.Empty
Dim objRandom As New Random()
For i As Integer = 0 To length Step 1
Dim x As Integer = objRandom.Next(1, chara.Length)
If Not randomString.Contains(chara.GetValue(x).ToString()) Then
randomString += chara.GetValue(x)
Else
i = i - 1
End If
Next
Return randomString
End Function
This all works great on my local visual studio run. But when i upload to my webserver several of the items get the same values.
This is the output on live server:
> Biljettinnehavare: 1 | 1XIh4YqBlHmipkPKV576C
> Biljettinnehavare: 2 | 1XIh4YqBlHmipkPKV576C
> Biljettinnehavare: 3 | 1XIh4YqBlHmipkPKV576C
> Biljettinnehavare: 4 | 1XIh4YqBlHmipkPKV576C
> Biljettinnehavare: 5 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 6 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 7 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 8 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 9 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 10 | qvmupeZhcoQ9YgOWtCLN4
> Biljettinnehavare: 11 | DdxK4jibcu9s7gXJw6a3m
> Biljettinnehavare: 12 | DdxK4jibcu9s7gXJw6a3m
> Biljettinnehavare: 13 | DdxK4jibcu9s7gXJw6a3m
> Biljettinnehavare: 14 | DdxK4jibcu9s7gXJw6a3m
> Biljettinnehavare: 15 | 32SWpkFfdgbqMtJGa1siw
> Biljettinnehavare: 16 | 32SWpkFfdgbqMtJGa1siw
Dont really know what is causing this problem. Any ideas?
Is the server executing the loop so quick and basing it on the clock makes the same values appear, what would be the way to counter that in that case?

Define your variable as:
Static objRandom As System.Random = New System.Random()
as in the answer Random integer in VB.NET

Related

Reverse Number in VB.Net

I want Reverse Number: example:
Textbox1.Text = 2 14 21 22 34 44
a deployment algorithm to do this. make
Expected Output: All Combination possible Reverse.
2 41 21 22 34 44
2 14 12 22 34 44
2 14 21 22 43 44
2 14 21 22 34 44
2 41 12 22 34 44
2 41 12 22 43 44
and so on...
2 14 21 22 34 44
What I try: it works, but it does not carry all the possible combinations, as in the above model.
Dim r As Integer
Public Function Reverse(rn As Integer)
Dim value As Integer
Dim values As New List(Of String)
For Each strValue As String In TextBox1.Text.Split(" ".ToCharArray, StringSplitOptions.RemoveEmptyEntries)
If Integer.TryParse(strValue.Trim, value) Then
values.Add(value)
End If
Next
Dim numbers = Val(TextBox1.Text)
Dim result As Integer
While numbers > 0
rn = numbers Mod 10
result = result * 10 + rn
numbers = numbers \ 10
End While
Reverse = result
End Function
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
TextBox2.Text = Reverse(r & " ")
End Sub

Adding to every other array position MS Access

I'm needing to take one array (firstArray) and input into a second array (secondArray). However, the first four fields are the same value. After the first four positions, it begins to alternate in values.
Example:
firstArray
+---------+
| ID# |
| Name |
| month1 |
| month2 |
| month3 |
| etc... |
+---------+
secondArray
+----------+
| ID# |
| Name |
| month1 |
| month2 |
| NewField |
| month3 |
| NewField |
| month4 |
| etc... |
+----------+
I'm fairly new to VBA, so I apologize for the awful code.
Code so far:
Dim i As Integer
i = 0
Dim j As Integer
ReDim secondArray(0 To (fieldCount - 4) * 2)
Dim finalCountDown As Integer
finalCountDown = (fieldCount - 4) * 2
secondArray(0) = firstArray(0)
secondArray(1) = firstArray(1)
secondArray(2) = firstArray(2)
secondArray(3) = firstArray(3)
i = 3
j = 3
Do Until i > finalCountDown
i = i + 1
secondArray(i) = "NewField"
i = i + 1
j = j + 1
secondArray(i) = firstArray(j)
Loop
I also have a MsgBox to iterate through and output my fields:
'//------ testing output
i = 0
For i = 0 To finalCountDown
MsgBox secondArray(i)
Next i
I appreciate any help! If there's any confusion, I'll gladly try to explain some more!
EDIT:
The two arrays are of different size but are dynamic. firstArray is firstly set to 20 positions while secondArray is originally set to 32 positions. (These are calculated each time this process is ran with the archived data being pulled. This allows my users to add data and not have to worry about having to manually add in the values to my arrays.)
EDIT2:
I've added Erik's portion to my code with a few alterations. I also added a separate counter for my firstArray in order to make sure it's inputting the correct rows into the correct positions of my secondArray.
EDIT3:
Here is the code that ended up working for me:
Dim i As Integer
i = 0
Dim j As Integer
'removed the " - 4"
ReDim secondArray(0 To (fieldCount * 2))
Dim finalCountDown As Integer
'removed the " - 4"
finalCountDown = (fieldCount * 2)
secondArray(0) = firstArray(0)
secondArray(1) = firstArray(1)
secondArray(2) = firstArray(2)
secondArray(3) = firstArray(3)
i = 3
'created own counter for firstArray
j = 3
Do Until i > finalCountDown
i = i + 1
secondArray(i) = "NewField"
i = i + 1
j = j + 1
secondArray(i) = firstArray(j)
Loop
The error I was getting was due "Subscript not in Range" due to the fact that my finalCountDown variable was less than my array needed to be. Allowing the variable to become larger than my array allowed my array to finish iterating through itself and now inputs the proper fields in the proper order.
I'm accepting Erik's answer as it was the stepping stone to answering the question!
For the adjusted code, you can do a simple check to check if the j value is valid:
Dim i As Integer
i = 0
Dim j As Integer
ReDim secondArray(0 To (fieldCount - 4) * 2)
Dim finalCountDown As Integer
finalCountDown = (fieldCount - 4) * 2
secondArray(0) = firstArray(0)
secondArray(1) = firstArray(1)
secondArray(2) = firstArray(2)
secondArray(3) = firstArray(3)
i = 3
j = 3
Do Until i > finalCountDown
i = i + 1
finalArray(i) = "NewField"
i = i + 1
j = j + 1
If j => LBound(colheaders) And j <= UBound(colHeaders) Then
finalArray(i) = colHeaders(j)
End If
Loop

Datagridview add column data if it contain number

I've a datagridview like this:
------------------------
| S.N |Data1 | Data2|
| 1 | - | 10 |
| 2 | 4 | 2 |
| 3 | 2 | - |
| 4 | 9 | - |
I want result like this:
------------------------
| S.N |Data1 | Data2|
| 1 | - | 10 |
| 2 | 4 | 2 |
| 3 | 2 | - |
| 4 | 9 | - |
| total | 15 | 12 |
-----------------------
I've tried this:
Dim data1 As double = 0
Dim data2 As double = 0
For i As Integer = 0 To DataGridView1.RowCount - 1
data1 += Val(CDbl(DataGridView1.Rows(i).Cells(1).Value))
data2 += Val(CDbl(DataGridView1.Rows(i).Cells(2).Value))
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)
But it has shown an error:
Can I extract number only from datagridview and display sum of them
and add to the last row?
And now I get my answer:
Dim data1 As double = 0
Dim data2 As double = 0
For j As Integer = 0 To DataGridView1.RowCount - 1
If Regex.IsMatch(DataGridView1.Rows(j).Cells(1).Value, "^[0-9 ]+$") Then
data1 += Val(CDbl(DataGridView1.Rows(j).Cells(1).Value))
End If
If Regex.IsMatch(DataGridView1.Rows(j).Cells(2).Value, "^[0-9 ]+$") Then
data2 += Val(CDbl(DataGridView1.Rows(j).Cells(2).Value))
End If
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)
This checks for nulls and ensures the data is numeric.
Dim data1 As double = 0
Dim data2 As double = 0
For i As Integer = 0 To DataGridView1.RowCount - 1
If Not IsDbNull(DataGridView1.Rows(i).Cells(1).Value) AndAlso IsNumeric(DataGridView1.Rows(i).Cells(1).Value) Then data1 += Val(CDbl(DataGridView1.Rows(i).Cells(1).Value))
If Not IsDbNull(DataGridView1.Rows(i).Cells(2).Value) AndAlso IsNumeric(DataGridView1.Rows(i).Cells(1).Value) Then data2 += Val(CDbl(DataGridView1.Rows(i).Cells(2).Value))
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)

Summing values based on type then on Month

I have a List<Object> where Object contains Name, Month, Type, Value.
is it possible to sum all the Value based on type, and then based on month?
I am using .NET 3.0 in VB.NET
I was doing withe like 4 For loops, but its taking a while to run.
Is there a quicker way?
For clarification, I have something like this:
Name | Month | Type | Value
-----------------------------
hello | Jan | A | 1
hello | Jan | A | 2
hello | Jan | B | 2
hello | Feb | A | 3
hello1 | Jan | A | 6
hello1 | Jan | A | 2
hello1 | Jan | B | 2
hello1 | Feb | A | 3
I want to produce it into this
Name | Month | Type | Value
---------------------------
hello | Jan | A | 3
hello | Jan | B | 2
hello | Feb | A | 3
hello1 | Jan | A | 8
hello1 | Jan | B | 2
hello1 | Feb | A | 3
If LINQ is not possible:
You could use Dictionarys to hold the month-values and the type-values. So you only need one loop to fill all. Here is an example:
Foo is your object and FooType is your type:
Class Foo
Public Enum FooType As Int32
FirstType = 1
SecondType = 2
ThirdType = 3
FourthType = 4
FifthType = 5
End Enum
Public Property Name As String
Public Property Month As Date
Public Property type As FooType
Public Property value As Double
End Class
load some sample-data:
Dim monthRnd As New Random(Date.Now.Millisecond)
Dim yearRnd As New Random(Date.Now.Millisecond)
Dim valueRnd As New Random(Date.Now.Millisecond)
Dim fooTypeRnd As New Random(Date.Now.Millisecond)
Dim allFoos As New List(Of Foo)
For i As Int32 = 1 To 1000
Dim foo As New Foo
foo.Name = i & ". Foo"
foo.type = CType(fooTypeRnd.Next(1, 5), Foo.FooType)
foo.Month = New Date(2000 + yearRnd.Next(0, 12), monthRnd.Next(1, 12), 1)
foo.value = valueRnd.Next(1, 10000) * valueRnd.NextDouble()
allFoos.Add(foo)
Next
Fill total value, grouped by type and by month:
Dim sumTotal As Double = 0D
Dim monthSums As New Dictionary(Of Date, Double)
Dim typeSums As New Dictionary(Of Foo.FooType, Double)
For Each f As Foo In allFoos
sumTotal += f.value
If typeSums.ContainsKey(f.type) Then
typeSums(f.type) += f.value
Else
typeSums.Add(f.type, f.value)
End If
If monthSums.ContainsKey(f.Month) Then
monthSums(f.Month) += f.value
Else
monthSums.Add(f.Month, f.value)
End If
Next
Now you can access these values easily via Dictionary key.
For example:
Dim feb2010Value As Double = 0d
Dim feb2010 As New Date(2010, 2, 1)
If monthSums.ContainsKey(feb2010) Then
feb2010Value = monthSums(feb2010)
End If
I’m still not sure what you want but your example makes it seem as if you group by name and by month and by type at the same time.
Either way, that’s an aggregation into a group. The following should work.
Dim result = From obj In objects _
Group obj By obj.Name, obj.Month, obj.Type Into _
Value = Sum(obj.Value) _
Select Name, Month, Type, Value
However, you shouldn’t use a List(Of Object) – use the correct object type instead.
(Untested, haven’t got VB handy so the actual syntax can deviate in small ways.)

VB.NET - Removing a number from a random number generator

I am trying to create a lottery simulator. The lottery has 6 numbers, the number generated must be between 1 - 49 and cannot be in the next number generated. I have tried using the OR function but I'm not entirely sure if I am using it properly. Any help would be great. Thanks.
Public Class Form1
Private Sub cmdRun_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRun.Click
''#Creates a new Random class in VB.NET
Dim RandomClass As New Random()
''####################################
Dim RandomNumber1 As Integer
RandomNumber1 = RandomClass.Next(1, 49)
''#Displays first number generated
txtFirst.Text = (RandomNumber1)
''####################################
Dim RandomNumber2 As Integer
RandomNumber2 = RandomClass.Next(1, 49)
If RandomNumber2 = RandomNumber1 Then
RandomNumber2 = RandomClass.Next(1, 49)
End If
''#Displays second number generated
txtSecond.Text = (RandomNumber2)
''####################################
Dim RandomNumber3 As Integer
RandomNumber3 = RandomClass.Next(1, 49)
If RandomNumber3 = RandomNumber2 Or RandomNumber2 Then
RandomNumber3 = RandomClass.Next(1, 49)
End If
''#Displays third number generated
txtThird.Text = (RandomNumber3)
''####################################
Dim RandomNumber4 As Integer
RandomNumber4 = RandomClass.Next(1, 49)
If RandomNumber4 = RandomNumber3 Or RandomNumber2 Or RandomNumber1 Then
RandomNumber4 = RandomClass.Next(1, 49)
End If
''#Displays fourth number generated
txtFourth.Text = (RandomNumber4)
''####################################
Dim RandomNumber5 As Integer
RandomNumber5 = RandomClass.Next(1, 49)
If RandomNumber5 = RandomNumber4 Or RandomNumber3 Or RandomNumber2 Or RandomNumber1 Then
RandomNumber5 = RandomClass.Next(1, 49)
End If
''#Displays fifth number generated
txtFifth.Text = (RandomNumber5)
''####################################
Dim RandomNumber6 As Integer
RandomNumber6 = RandomClass.Next(1, 49)
If RandomNumber6 = RandomNumber5, RandomNumber4, RandomNumber3, RandomNumber2, RandomNumber1 Then
RandomNumber6 = RandomClass.Next(1, 49)
End If
''#Displays sixth number generated
txtSixth.Text = (RandomNumber6)
End Sub
Instead of "If", use "While" - in other words, keep generating random numbers until you find a new one. Currently if you get a duplicate and then get a duplicate on the second attempt, you'll keep going.
Also, while I'm no VB expert, I believe you'll need to specify each comparison in full, so instead of this:
If RandomNumber3 = RandomNumber2 Or RandomNumber2 Then
RandomNumber3 = RandomClass.Next(1, 49)
End If
you need:
While RandomNumber3 = RandomNumber1 Or RandomNumber3 = RandomNumber2 Then
RandomNumber3 = RandomClass.Next(1, 49)
End While
There are alternatives here - such as generating the numbers 1-49, shuffling them, and then fetching the first 6 results... or keeping to the "pick until there's a new one" but keep the results in a set. Either way you could avoid having quite so much code duplication.
You don't just need a random number generator here, you need one in conjunction with a shuffling algorithm.
Create an array of N items (we'll use seven for our example), each containing the integer relating to its position:
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+
<pool(7)
and set the pool size to 7.
Then generate your random number, based on the pool size (i.e., get a number from 1 to 7). Let's say your generator returns 3.
Pull out the value at position 3 then replace that with the top value, then reduce the pool size:
+---+---+---+---+---+---+---+
| 1 | 2 | 7 | 4 | 5 | 6 | 7 | -> 3
+---+---+---+---+---+---+---+
<pool(6)
Then you just keep doing this until you've gotten the quantity of values required. If our lotto was 5 from 7:
+---+---+---+---+---+---+---+
| 1 | 2 | 7 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+
<pool(7)
rnd(7) returns 3
+---+---+---+---+---+---+---+
| 1 | 2 | 7 | 4 | 5 | 6 | 7 | -> 3
+---+---+---+---+---+---+---+
<pool(6)
rnd(6) returns 1
+---+---+---+---+---+---+---+
| 6 | 2 | 7 | 4 | 5 | 6 | 7 | -> 1
+---+---+---+---+---+---+---+
<pool(5)
rnd(5) returns 5
+---+---+---+---+---+---+---+
| 6 | 2 | 7 | 4 | 5 | 6 | 7 | -> 5
+---+---+---+---+---+---+---+
<pool(4)
rnd(4) returns 2
+---+---+---+---+---+---+---+
| 6 | 4 | 7 | 4 | 5 | 6 | 7 | -> 2
+---+---+---+---+---+---+---+
<pool(3)
rnd(3) returns 1
+---+---+---+---+---+---+---+
| 7 | 4 | 7 | 4 | 5 | 6 | 7 | -> 6
+---+---+---+---+---+---+---+
<pool(2)
and there you have it, 5-from-7 numbers (3,1,5,2,6) extracted with no possibilities of duplicates and an efficient O(n) method for getting them. Any solution that relies on just getting random numbers and checking if they've already been used will be less efficient.
Here's another option using LINQ if you have VB2008:
Dim rnd As New Random()
Dim randomNumbers = From n in Enumerable.Range(1, 49) _
Order By rnd.Next() _
Select n _
Take 6
'Do something with the numbers here
This is a simple way to do it. If using the Random class is not random enough, then you may have to choose an alternative method.
You have to change the name of the textbox I'm using to the one you're using.
Dim rand As New Random
Dim winnum As New List(Of Integer)
Dim num, counter As Integer
Dim result As String = ""
Do
num = rand.Next(1, 49)
If winnum.Contains(num) Then
Do
num = rand.Next(1, 49)
Loop Until winnum.Contains(num) = False
End If
winnum.Add(num)
counter += 1
Loop Until counter = 6
'Extracting and displaying the numbers from the array
For n As Integer = 0 To 5
result = winnum(n) & " " & result
Next
'The textbox I'm using to display the result is result.text
result.Text = result
You can also use code as another fellow suggested above. In the code below, numbers are generated randomly and are removed from a pool of numbers until the required quantity is reached. Then the numbers left are then displayed. However this is not such a good way for generating numbers for lottery as the sequence of numbers are somehow predictable, but they are unique. Here is the code:
Dim rand As New Random, winnum As New List(Of Integer)
Dim num As Integer, result As String = ""
For n As Integer = 1 To 49
winnum.Add(n)
Next
Do
num = rand.Next(1, 49)
If winnum.Contains(num) Then
winnum.Remove(num)
End If
Loop Until winnum.Count = 7
For n As Integer = 0 To 5
result = winnum(n) & " " & result
Next
a.Text = result
I'd go for something like (in C#)
public static IEnumerable<int> Lotto(int max)
{
var random = new Random((int)DateTime.Now.Ticks);
var numbers = new List<int>(Enumerable.Range(1, max));
while(numbers.Count > 0)
{
int index = random.Next(1, numbers.Count) - 1;
yield return numbers[index];
numbers.RemoveAt(index);
}
}
static void Main(string[] args)
{
var lotto = Lotto(49).GetEnumerator();
lotto.MoveNext();
int r1 = lotto.Current;
lotto.MoveNext();
int r2 = lotto.Current;
lotto.MoveNext();
int r3 = lotto.Current;
Console.WriteLine("{0} {1} {2}", r1, r2, r3 );
}
Instead of picking random numbers and check for duplicates, you can simply loop through the numbers and check the odds for each number to be picked against a random number:
Dim count As Integer = 6 ' How many numbers to pick
Dim pos As Integer = 1 ' Lowest value to pick from
Dim items As Integer = 49 ' Number of items in the range
Dim rnd As New Random()
Dim result As New List(Of Integer)()
While count > 0
If rnd.Next(items) < count Then
result.Add(pos)
count -= 1
End If
pos += 1
items -= 1
End While
The list result now contains six numbers without duplicates, randomly picked from the range 1-49. As an extra bonus the numbers in the list are already sorted.
I think shuffling is the fastest alternative too. But easier to read is your approach in combination with a collections's contains function:
Dim numbers As New List(Of Int32)
For i As Int32 = 1 To 6
Dim containsNextNumber As Boolean = False
While Not containsNextNumber
Dim rnd As New Random(Date.Now.Millisecond)
Dim nextNumber As Int32 = rnd.Next(1, 50)
If Not numbers.Contains(nextNumber) Then
numbers.Add(nextNumber)
containsNextNumber = True
End If
End While
Next
numbers.Sort() 'sort the numbers from low to high