how to shuffle array in VB? - vb.net

I'm trying to create and application which will shuffle an string array and produce 2 totally different versions where no element will match each other
like for example the initial array is A, B, C, D, E than the shuffled array must be B, D, E, A, C.
In my case when I suffle them and try to produce an output I get shuffled array but they are completely identical to each other. It seems like the values in last array override the values of the previous ones.
I tried to protect them but I don't know how to do it. Please can anybody give me a hint about what am I doing wrong?
Dim myArray() As String = {"A", "B", "C", "D", "E"}
This is the code of the button which triggers shuffle
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RendomOutput1(myArray)
End Sub
End Class
THis is the function that shuffles first array:
Sub RendomOutput1(ByVal x() As String)
Dim t As Integer
Dim Temp As String
For i As Integer = 0 To x.Count - 1
Dim rnd As New Random
t = rnd.Next(0, x.Count - 1)
Temp = x(t)
x(t) = x(i)
x(i) = Temp
Next
RandomOutput2(x)
End Sub
This is the function which produces another array and prints the result:
Sub RendomOutput2(ByRef y() As String)
Dim y1() As String = y' May be I shall lock or somehow protect y1 here?
'Lock(y1) doesn't work
Dim t As Integer
Dim Temp As String
For i As Integer = 0 To y.Count - 1
Dim rnd As New Random
t = rnd.Next(0, y.Count - 1)
Temp = y(t)
y(t) = y(i)
y(i) = Temp
Next
For i As Integer = 0 To x.Count - 1
Label1.Text &= y1(i) & " IS NOT " & y(i) & vbCrLf
Next
End Sub
IN the result arrays y1 and y are different from initial but identical to each other. Does anybody know how can I make them different. Probably lock y1 array or something. Thank you in advance

This line
Dim y1() As String = y
doesn't create a new array - it creates a reference to an existing array. So you'll have two array references (y and y1) but only one array (both references point to the same array). When you make changes to y those changes are visible through y1 because both of them refer to the same underlying array.
What you need is 2 distinct array instances where the data held be the arrays are duplicated (that is, you need 2 array references that point to 2 different arrays). Then changes made to one array will not affect the other array.
For example:
' Create new array from the input array
Dim y1() As String = new String(y.Count-1){}
For i As Integer = 0 To y.Count-1
y1(i) = y(i)
Next i
Alternatively, you can just clone the array:
Dim y1() As String = y.Clone()
Behind the scenes this results in the same thing.

Here's a simple routine for shuffling any array:
Public Sub Shuffle(Of T)(ByRef A() As T)
Dim last As Integer = A.Length - 1
Dim B(last) As T
Dim done(last) As Byte
Dim r As New Random(My.Computer.Clock.TickCount)
Dim n As Integer
For i As Integer = 0 To last
Do
n = r.Next(last + 1)
Loop Until Not done(n)
done(n) = 1
B(i) = A(n)
Next
A = B
End Sub
Note that some elements could remain at their original index by chance.

Related

Shell Sort Algorithm

I am attempting to implement an array using the shell sort algorithm. The program will sort the array and output each element to the Listbox after the button was clicked. However, the first item output is always 0. I have included a piece of my source code and a photo of the form below;
Dim randGen As New Random()
Dim unstArray() As Integer
Dim unstArrayCopy() As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Generates random number to save in array.
Dim i As Integer = CInt(TextBox1.Text)
ReDim unstArray(i)
ReDim unstArrayCopy(i)
For x = 0 To i
unstArray(x) = randGen.Next(1, 10001)
Next
Array.Copy(unstArray, unstArrayCopy, i)
End Sub
Private Sub ShllSrtBtn_Click(sender As Object, e As EventArgs) Handles shllSrtBtn.Click
shellsort(unstArrayCopy, unstArrayCopy.GetUpperBound(0))
End Sub
Sub shellsort(ByRef shellSort() As Integer, ByVal max As Integer)
Dim stopp%, swap%, limit%, temp%, k%
Dim x As Integer = CInt((max / 2) - 1)
Do While x > 0
stopp = 0
limit = max - x
Do While stopp = 0
swap = 0
For k = 0 To limit
If shellSort(k) > shellSort(k + x) Then
temp = shellSort(k)
shellSort(k) = shellSort(k + x)
shellSort(k + x) = temp
swap = k
End If
Next k
limit = swap - x
If swap = 0 Then stopp = 1
Loop
x = CInt(x / 2)
Loop
For i = 0 To shellSort.GetUpperBound(0)
ListBox1.Items.Add(shellSort(i))
Next i
End Sub
The problem is here:
ReDim unstArray(i)
ReDim unstArrayCopy(i)
In VB, when you initialize an array, you must give it the maximum index you want to use, not the intended array length as in other languages like C#.
Because of that, your code creates an array of length i+1, but you only loop from 0 to i when filling the array. So the last element at index i will always be zero.
You should set the initializer in these lines to i-1.
VB Array Reference

Spliting large imported text file into a dynamic 2d array in VB 2015

I am currently trying to code a way to read a text file filled with LOTS of data and create a dynamic 2d array to hold each numeric value in its own cell. The text file has data formatted like this
150.00 0.00030739 0.00030023 21.498 0.00024092
150.01 0.00030778 0.00030061 21.497 0.00024122
150.02 0.00030818 0.00030100 21.497 0.00024151
150.03 0.00030857 0.00030138 21.496 0.00024181
150.04 0.00030896 0.00030177 21.496 0.00024210
150.05 0.00030935 0.00030216 21.496 0.00024239
where the spaces are denoted by a vbTab. This is what I have so far.
Dim strfilename As String
Dim num_rows As Long
Dim num_cols As Long
Dim x As Integer
Dim y As Integer
strfilename = "Location of folder holding file" & ListBox1.SelectedItem
If File.Exists(strfilename) Then
Dim sReader As StreamReader = File.OpenText(strfilename)
Dim strLines() As String
Dim strLine() As String
'Load content of file to strLines array
strLines = sReader.ReadToEnd().Split(Environment.NewLine)
'redimension the array
num_rows = UBound(strLines)
strLine = strLines(0).Split(vbTab)
num_cols = UBound(strLine)
ReDim sMatrix(num_rows, num_cols)
'Copy Data into the array
For x = 0 To num_rows
strLine = strLines(x).Split(vbTab)
For y = 0 To num_cols
sMatrix(x, y) = strLine(y).Trim()
Next
Next
End If
When I run this code I get only the first number in the first column of the array and everything else is missing. I need something that shows all of the values. Any help or guidance would be greatly appreciated
Edit:
Here's a picture of what I'm seeing.
What I'm Seeing
You don't need to read all the data in one lump - you can read it line-by-line and process each line.
I assume that the data is machine-generated so that you know there are no errors. I did however put in a check for the required quantity of items on a line.
I copied the data you gave as an example and edited it to change the spaces to tabs.
Option Strict On
Option Infer On
Imports System.IO
Module Module1
Class Datum
Property Time As Double
Property X As Double
Property Y As Double
Property Z As Double
Property A As Double
Sub New(t As Double, x As Double, y As Double, z As Double, a As Double)
Me.Time = t
Me.X = x
Me.Y = y
Me.Z = z
Me.A = z
End Sub
Sub New()
' empty constructor
End Sub
Overrides Function ToString() As String
Return String.Format("(T={0}, X={1}, Y={2}, Z={3}, A={4}", Time, X, Y, Z, A)
' if using VS2015, you can use the following line instead:
' Return $"T={Time}, X={X}, Y={Y}, Z={Z}, A={A}"
End Function
End Class
Function LoadData(srcFile As String) As List(Of Datum)
Dim data = New List(Of Datum)
Using sr As New StreamReader(srcFile)
While Not sr.EndOfStream()
Dim thisLine = sr.ReadLine()
Dim parts = thisLine.Split({vbTab}, StringSplitOptions.RemoveEmptyEntries)
If parts.Count = 5 Then
data.Add(New Datum(CDbl(parts(0)), CDbl(parts(1)), CDbl(parts(2)), CDbl(parts(3)), CDbl(parts(4))))
End If
End While
End Using
Return data
End Function
Sub Main()
Dim src = "C:\temp\testdata2.txt"
Dim myData = LoadData(src)
For Each datum In myData
Console.WriteLine(datum.ToString())
Next
Console.ReadLine()
End Sub
End Module
As you can see, if you use a class to hold the data then you can usefully give it other methods like .ToString().
Option Strict On makes sure that you do not do anything which is meaningless, like trying to store a string in a numeric data type. It is strongly recommended that you set Option Strict On as the default for all projects.
Option Infer On lets the compiler figure out what data type you want when you use something like Dim k = 1.0, so you don't have to type Dim k As Double = 1.0, but note that if you used Dim k = 1 it would infer k to be an Integer.
Once the data is in instances of a class in a list, you can use LINQ to process it in a fairly easy-to-read fashion, for example you could do
Console.WriteLine("The average X value is " & (myData.Select(Function(d) d.X).Average()).ToString())

VB.NET combination Array x2

I would like all possible combinations from two string arrays.
Both arrays must have same length.
Result must keep order
For example :
dim lStr1() as string = {"One", "Two", "Three"}
dim lStr2() as string = {"EditOne", "EditTwo", "EditThree"}
dim res() as string = myAwesomeFunction(lStr1, lStr2)
// res :
One Two Three
One Two EditThree
One EditTwo Three
One EditTwo EditThree
EditOne Two Three
EditOne Two EditThree
EditOne EditTwo Three
EditOne EditTwo EditThree
It's like the binary composition of 2 arrays of strings.
Here's another solution. Since only 2 arrays are involved, we can bit-fiddle to get all of the "combinations". The & " " is just to format the output to match the example.
Private Function myAwesomeFunction(Array1() As String, Array2() As String) As String()
If Array1.Length <> Array2.Length Then
Throw New ArgumentException("Array lengths must be equal.")
End If
Dim combos(CInt(2 ^ Array1.Length) - 1) As String
For i As Integer = 0 To combos.Count - 1
For j = 0 To Array1.Length - 1
If (i And (1 << j)) > 0 Then
combos(i) += Array2(j) & " "
Else
combos(i) += Array1(j) & " "
End If
Next
Next
Return combos
End Function
The following code will produce the array in your example. It should work for any pair of input arrays. The function checks that the input arrays are of the same length.
The GetPermutations function is taken from a more general class I use for generating permutations of numbers. It returns arrays of total Integers between 0 and choose - 1, and being an Iterator function, it returns the next array each time it is called.
In order to match your example, I returned an array of String where each element is a single string consisting of each of the selected strings separated by spaces. You may find it more useful to return a List(Of String()) or even a List(Of List(Of String))
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lStr1() As String = {"One", "Two", "Three"}
Dim lStr2() As String = {"EditOne", "EditTwo", "EditThree"}
Dim res() As String = myAwesomeFunction(lStr1, lStr2)
End Sub
Function MyAwesomeFunction(lStr1() As String, lStr2() As String) As String()
Dim combos As New List(Of String)
If lStr1.Length <> lStr2.Length Then Throw New ArgumentException("Arrays must have the same length")
For Each combo() As Integer In GetPermutations(lStr1.Length, 2)
Dim elem As New List(Of String)
For i As Integer = 0 To combo.Length - 1
elem.Add(If(combo(i) = 0, lStr1(i), lStr2(i)))
Next
combos.Add(String.Join(" ", elem))
Next
Return combos.ToArray
End Function
Public Iterator Function GetPermutations(choose As Integer, total As Integer) As IEnumerable(Of Integer())
Dim totals() As Integer = Enumerable.Repeat(Of Integer)(total, choose).ToArray
Dim value(choose - 1) As Integer
Do
Yield value
For index As Integer = choose - 1 To 0 Step -1
value(index) += 1
If value(index) < totals(index) Then Continue Do
value(index) = 0
Next
Exit Do
Loop
End Function

For loop make new variables for you - VB.Net

I'm trying to make a for loop for will make a new variable for me, every step. I want something like this. What ever step I am on, say, x = 2, it Dims newVar2, if x = 3: Dim newVar3
Is there any way to do that? I was hoping something like, Dim newVar & x would work, but of course now.
I was trying to do it as an array, but I'm not sure how to do that, or ReDimming, so examples would be great!
To create a collection of variable values inside a for loop, you should use a List(Of t) object or something similar (For Example Dictionary).
To do this with a List(Of t) you can do the following :
Dim varList As New List(Of Integer)
For i As Integer = 0 To 10
varList.add(i)
Next
Or if you want to do it with the variable names you mentioned, try :
Dim varList As New List(Of String)
For i As Integer = 0 To 10
varList.add("newVar" & i)
Next
To retrieve the value from a List use the following : Dim result As String = varList(0)
Alternatively you can use a Dictionary object to store Key/Value pairs :
Dim varList As New Dictionary(Of String, Integer)
For i As Integer = 0 To 10
Dim k As Integer = 0
varList.add("newVar" & i, k)
Next
Becareful though as a Dictionary object can only contain unique Keys. To return the value find it as : Dim result As Integer = varList("newVar0")
basic array:
Dim Arr(1000) As Integer
For i As Integer = 0 To 999
Arr(i) = YYYYY
Next
trick for dynamic size:
Dim max As Integer = XXXXXX
Dim Arr(1000) As Integer
For i As Integer = 0 To max
'if too small, Increasing array without loss old data
If Arr.Length = i Then
ReDim Preserve Arr(Arr.Length + 1000)
End If
Arr(i) = YYYYY
Next
or, use list:
Dim max As Integer = XXXXXX
Dim list As New List(Of Integer)
For i As Integer = 0 To max
list.Add(YYYYY)
Next
The other answers are technically correct, but you probably don't need the iteration loops. You can probably do this in a single line of code:
Dim varList As Dictionary(Of String, String) = Enumerable.Range(0, 10).ToDictionary(Function(k) "newVar" & k, Function(v) "Some value for newVar" & v)
Dim myInts As New List(Of Int)
For i = 0 To 10
myInts.Add(i)
Next

How to get each value in an array and show it in a listbox

Hi I am new to VB and I have problems with using array. My code is like that.
This is class FindFactorsObject.vb
Public Sub FindFactors()
count = 0
temp = Convert.ToInt32(Math.Sqrt(_x))
For i As Integer = 1 To temp
If _x Mod i = 0 Then
ReDim array(count)
array(count) = i
count += 1
End If
Next
So I created an array and stored the results. Now I want to display each value in my array in Form.vb and if it is possible can somebody teach me how to make delay for each of the displayed value. Thanks very much
Always declare your variables, if possible to their exact types, you think they will take care of. When you say 'Now I want to display each value in my array in Form.vb' I understood literally: in the Form so, we will print them on your form
Public Sub FindFactors(_x As Integer)
Dim temp As Integer = Convert.ToInt32(Math.Sqrt(_x))
Dim l As New List(Of Integer)
For i As Integer = 1 To temp
If _x Mod i = 0 Then
l.add(i)
End If
Next
Dim pf As New PointF(20, 20)
For Each i As Integer In l
creategraphics.drawstring(i.ToString, New font(font.fontFamily, 24), brushes.cadetblue, pf)
pf = New PointF(pf.X, pf.Y + 30)
Next
End Sub