Alternative to Random.Next method [duplicate] - vb.net

This question already has answers here:
How to Choose Random number from given list of numbers in VB.Net
(4 answers)
Closed 4 years ago.
In visual basic, is there a method that will allow me to select a random number from a list of numbers, rather than selecting a random number between two numbers?
In other words, I want something like Random().Next(1, 3, 4, 6, 7) where it will select a random number from those numbers (so selecting 2 is not an option)
I've looked here, but can't seem to find anything.

Try the following:
Imports System
Public Module Module1
Private Function NextRandom(ParamArray numbers() As Integer) As Integer
Dim Result As Integer = Integer.MinValue
If numbers.Length > 0 Then
Dim rnd As New Random
Dim i As Integer = rnd.Next(0, numbers.Length)
Result = numbers(i)
End If
Return Result
End Function
Public Sub Main()
Console.writeline("Your next number is: {0}", NextRandom(1, 3, 5, 6, 7, 8, 9))
End Sub
End Module
More info and examples here
Working example of the code here
Hope this helps.

If you want each value in your list only once then just shuffle your list.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst As New List(Of Integer) From {1, 3, 4, 6, 7}
Dim shuffledList As List(Of Integer) = lst.OrderBy(Function(i) Rnd.Next()).ToList()
For Each i In shuffledList
Debug.Print(i.ToString)
Next
End Sub
You get a different order each time you click the button.

Define your list as an array:
Dim List = New Integer() {Your numbers here}
Then use the standard random.next to generate an index for the array:
Dim generator As New Random
Dim index As Integer
index = generator.Next(0, List.length)
Then define your random number as the number that corresponds to the index in the array:
Dim randNumber as Integer
randNumber = List(index)

Related

Generate a sequence of 5 random numbers

this code generates a single number, how could I generate more?
Dim randomNumber As Integer = rnd.Next(0, 81)
I would like to generate more random numbers using this code, but how could I do that?
As you generate your 5 random numbers, you need a place to store each number. I chose a List(Of T) because I don't have to know how many items I want to add in advance. You could also use an array.
When you instantiate the Random class without a seed then the class uses the system clock as the seed. This is the usual way to do it.
Private Sub OPCode(URL As String)
Dim Rnd As New Random() 'No seed!
Dim lst As New List(Of Integer)
For i = 0 To 4
lst.Add(Rnd.Next(0, 81))
Next
For Each i In lst
TextBox1.Text &= i.ToString & vbCrLf
Next
End Sub

Arraylist.Contains Doesn't Return True VB.NET

comps.Contains doesn't return TRUE even though comps contains it.
I debugged it step by step and I can't see where the problem is.
By the way the purpose of the code is to show the pairs that sum up to SUM value. (If the sum is 5 and theres 1 and 4 then the code should return 1 and 4)
Public Function getPairs(ByVal array As ArrayList, ByVal sum As Integer)
Dim comps, pairs As New ArrayList
For index = 0 To array.Count - 1
If (comps.Contains(array(index)) = True) Then
pairs.Add(array(index))
Else
comps.Add(sum - array(index))
End If
Next
Return pairs
End Function
Sub Main()
' 1,3,2,5,46,6,7,4
' k = 5
'Dim arraylist As New ArrayList()
Console.Write("Enter your array :")
Dim arraylist As New ArrayList
arraylist.AddRange(Console.ReadLine().Split(","))
Console.Write("Enter the sum:")
Dim sum As Integer = Console.ReadLine()
getPairs(arraylist, sum)
Console.ReadKey()
End Sub
The ArrayList you populate from user input contains strings (results from splitting the user input string). The comps ArrayList contains integers (results from subtraction). When it tries to find the string "2" in the ArrayList that contains a 2, it fails.
You should convert your user input to integers so that you are comparing the same data types.
First, turn on Option Strict. Tools Menu -> Options -> Projects and Solutions -> VB Defaults. This will point out problems with your code and help you to avoid runtime errors.
ArrayList is not used much in new code but is around for backward compatibility. List(Of T) is a better choice for new code.
Module Module1
Sub Main()
' 1,3,2,5,46,6,7,4
' k = 5
'Dim arraylist As New ArrayList()
Console.Write("Enter your array :")
Dim arraylist As New ArrayList
'Option Strict would not allow this line to compile
'.Split takes a Char, the same c tells the compiler that "," is a Char
arraylist.AddRange(Console.ReadLine().Split(","c))
Console.Write("Enter the sum:")
'Option Strict would not allow a string to be dumped into an integer
Dim sum As Integer
Dim Pairs As New ArrayList
If Integer.TryParse(Console.ReadLine, sum) Then
'Your Function returns an array list but you
'throw it away by not setting up a variable to receive it
Pairs = getPairs(arraylist, sum)
Else
Console.WriteLine("Program aborted. Sum was not a number.")
End If
For Each item In Pairs
Console.WriteLine(item)
Next
Console.ReadKey()
End Sub
'Functions need a return data type in the declaration
Public Function getPairs(ByVal array As ArrayList, ByVal sum As Integer) As ArrayList
Dim comps, pairs As New ArrayList
For index = 0 To array.Count - 1
'I don't see how this can ever be true since comps is empty
If comps.Contains(array(index)) Then 'Since .Contains returns a Boolean, no = True is necessary
pairs.Add(array(index))
Else
'Ideally each item in array should be tested to see if it is a number
'You will get an exception if CInt fails
comps.Add(sum - CInt(array(index)))
'You never use the comps ArrayList
End If
Next
'The pairs ArrayList is empty
Return pairs
End Function
End Module
I don't see how this code could accomplish what you describe as your goal. I think you should start again. Talk through how you would accomplish your task. Then write it out on paper, not in code. Then you will see more clearly how to code your project.
The big problem is the original code is this line:
Dim comps, pairs As New ArrayList
That code creates two ArrayList reference variables, but only one ArrayList object. comps remains null/Nothing.
But beyond that, the ArrayList type has been dead since .Net 2.0 came out back in 2005... more than 10 years now. It only exists today for backwards compatibility with old code. Don't use it!
This is better practice, especially in conjunction with Option Strict and Option Infer:
Public Function getPairs(ByVal items As IEnumerable(Of Integer), ByVal sum As Integer) As IEnumerable(Of Integer)
Dim comps As New HashSet(Of Integer)()
Dim result As New List(Of Integer)()
For Each item As Integer In items
If Not comps.Add(item) Then
result.Add(sum - item)
End If
Next
Return result
End Function
Sub Main()
Console.Write("Enter your array: ")
Dim input As String = Console.ReadLine()
Dim list As List(Of Integer) = input.Split(",").Select(Function(item) CInt(item)).ToList()
Console.Write("Enter the sum: ")
Dim sum As Integer = CInt(Console.ReadLine())
Dim pairs = getPairs(list, sum).Select(Function(s) s.ToString())
Console.WriteLine("Pairs are: {0}", String.Join(", " pairs))
Console.ReadKey()
End Sub

Visual Basic, new to coding. Need to make a list of 100 integers create a shuffled list of 70 results

I'm new to coding and I have got firmly stuck on this.
I've created a list in Visual Basic with
Dim integerStable As New List(Of Integer)()
integerStable.Add(0)
integerStable.Add(1)
integerStable.Add(2)
'through to integerStable.Add(99)
I'm trying to keep this list (it can be shuffled as long as all numbers stay in the list in general) and create a 2nd list where it only has 70 results from that shuffle.
I need that list, so I can call on it to perform some tasks for me later.
Can anyone help me work out how to do this? Remember I'm new to coding, but I'll try to follow along.
One of the most efficient ways to create your list would be as follows:
Dim integerStable As New List(Of Integer)
For i = 1 To 100
integerStable.Add(i)
Next
That at least should save you a lot of typing!!
You could also do the following:
Dim integerStable As New List(Of Integer)
Dim i As Integer
While i <= 100
integerStable.Add(i)
i += 1
End While
**Note though that the latter example will give you 101 items as integer is initially set to 0 **
You also need to remember that the list will be 'indexed' from 0 NOT 1 which is an important thing to remember when it comes to manipulating the items with it.
It can be much simpler.
Private Shared PRNG As New Random
' 100 numbers starting at zero, in random order
Private listOnum As List(Of Integer) = Enumerable.Range(0, 100).OrderBy(Function(x) PRNG.Next).ToList
' list of 70 numbers from list of 100
Private list70 As List(Of Integer) = listOnum.Take(70).ToList
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'did it work?
Dim ct As Integer = 1
For Each n As Integer In list70
Debug.WriteLine("{0}. {1,3}", ct, n)
ct += 1
Next
End Sub
Enumerable.Range takes two arguments. The first is a start number and the second is a count, so in the example it created a list that started at 0 and ended with 99, 100 items. The OrderBy just sorted that list by random numbers.
list70 is created by taking the first 70 items from listOnum.
The Random, PRNG, is created that way so that there is only ONE random that is only initialized once. You can find many problems associated with the incorrect initialization of Random.
edit: Slightly different approach.
Private Shared PRNG As New Random
' 100 numbers starting at zero
Private listOnum As List(Of Integer) = Enumerable.Range(0, 100).ToList
' list of 70 random numbers from list of 100
Private list70 As List(Of Integer) = listOnum.OrderBy(Function(x) PRNG.Next).Take(70).ToList
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'did it work?
Dim ct As Integer = 1
For Each n As Integer In list70
Debug.WriteLine("{0}. {1,3}", ct, n)
ct += 1
Next
'recreate list of 70
list70 = listOnum.OrderBy(Function(x) PRNG.Next).Take(70).ToList
End Sub

VB.NET: Value of Type 'Integer' cannot be converted to 'System.Array'

In the below code I am getting the following error on line If (Not hash.Add(Numbers(Num))) Then Value of Type 'Integer' cannot be converted to 'System.Array'. What am I doing wrong?
Module Module1
Sub Main()
Dim array() As Integer = {5, 10, 12, 8, 8, 14}
' Pass array as argument.
Console.WriteLine(findDup(array))
End Sub
Function findDup(ByVal Numbers() As Integer) As Integer
Dim hash As HashSet(Of Array)
For Each Num In Numbers
If (Not hash.Add(Numbers(Num))) Then
Return (Num)
End If
Next
End Function
End Module
Inside findDup, this
Dim hash As HashSet(Of Array)
Should be
Dim hash As HashSet(Of Integer)
EDIT: As suggested by #Damien_The_Unbeliever, the code
This line
If (Not hash.Add(Numbers(Num))) Then
Should be
If (Not hash.Add(Num)) Then
You have created a hashset of Array, rather than a hashset of Integer. You could change it to Integer, and alter how you try to add things in your loop to:
Function findDup(ByVal Numbers() As Integer) As Integer
Dim hash As New HashSet(Of Integer)
For Each Num In Numbers
If (Not hash.Add(Num)) Then
Return (Num)
End If
Next
End Function
I am hoping you realize that it will only ever find the first duplicate, and doesn't return a value of any type if it doesn't find a duplicate.
You've declared hash to be HashSet(Of Array), which means that it holds arrays. But you're trying to add integers to it.
You need to either change its declaration (HashSet(Of Integer)) or change the call to Add (Add(Numbers)).
Which solution you use will depend on your intent. My guess is that you want to change the type of hash.
Is this what you mean to do?
Sub Main()
Dim someArray() As Integer = {5, 10, 12, 8, 7, 8, 8, 10, 14, 10}
' Pass array as argument.
Dim foo As List(Of Integer) = findDups(someArray)
'foo contains a list of items that have more than 1 occurence in the array
End Sub
Function findDups(ByVal Numbers() As Integer) As List(Of Integer)
Dim rv As New List(Of Integer)
For idx As Integer = 0 To Numbers.Length - 1
If Array.LastIndexOf(Numbers, Numbers(idx)) <> idx Then
If Not rv.Contains(Numbers(idx)) Then rv.Add(Numbers(idx))
End If
Next
Return rv
End Function

Getting the index of the largest integer in an array

I have an array of integers and I need to know the index of the largest number (not the actual value, just the index of whichever is highest).
However, if one or more indexes "tie" for the highest value, I need to have all of the indexes that share that high value.
I assume this function would need to return an array (since it could be one or more indexes), but I am not totally sure how to go about getting the more efficient solution.
If this is going to be a common thing you could write your own Extension. You should add some additional sanity/null checking but this will get you started:
Module Extensions
<System.Runtime.CompilerServices.Extension()> Function FindAllIndexes(Of T)(ByVal array() As T, ByVal match As Predicate(Of T)) As Integer()
''//Our return object
Dim Ret As New List(Of Integer)
''//Current array index
Dim I As Integer = -1
''//Infinite loop, break out when we no more matches are found
Do While True
''//Loop for a match based on the last index found, add 1 so we dont keep returning the same value
I = System.Array.FindIndex(array, I + 1, match)
''//If we found something
If I >= 0 Then
''//Append to return object
Ret.Add(I)
Else
''//Otherwise break out of loop
Exit Do
End If
Loop
''//Return our array
Return Ret.ToArray()
End Function
End Module
Then to call it:
Dim ints As Integer() = New Integer() {1, 2, 8, 6, 8, 1, 4}
Dim S = ints.FindAllIndexes(Function(c) c = ints.Max())
''//S now holds 2 and 4
If you are using .NET 3.5, you can use the Max() Extension function to easily find the highest value, and use Where to locate the matching records in your source array.
IList has an IndexOf member, which helps. This code is completely untested, and probably has at least one off-by-one error.
Public Function GetPostionsOfMaxValue(ByVal input() As Integer) As Integer()
Dim ints = New List(Of Integer)(input)
Dim maxval = ints.Max
Dim indexes As New List(Of Integer)
Dim searchStart As Integer = 0
Do Until searchStart >= ints.Count
Dim index = ints.IndexOf(maxval, searchStart)
If index = -1 Then Exit Do
indexes.Add(index)
searchStart = index + 1
Loop
Return indexes.ToArray
End Function