Modal Value, and Repetition - arrays

I want to make a modal value calculator, So it calculates the Modal value and its repetition
The idea is to make a list of data and its repetition like shown in any Graph.
This is code you I start with:
Public Class
Dim a1(100), a2(100), Rep(100), RepMer(100), AMer(100) As Single, n, count, m As Single, z, k, c, mars As Integer
n = InputBox("How many data?", "RepTest")
count = 0
For count = 0 To n - 1
a1(count) = InputBox("Add Value", "RepTest")
Next
z = n
For run = 0 To n - 1
mars = c
z = z - 1
k = 0
For moon = 0 To (n - 1)
If a1(z) = a1(moon) Then
k = k + 1
a2(run) = a1(z)
Rep(run) = Rep(run) + k
If Rep(run) > 2 Then
Rep(run) = Rep(run) - 1
End If
End If
Next
MsgBox(a2(run)), , "Modal Value")
MsgBox(Rep(run)),, "Repetition")
Next
End Class
However, If you make the massage box outside the main 2nd loop, you have to make another loop with the same value 0 To (n-1), to match data position in an Array.
what I want you to help me please is:
I have to save the modal value and the repetition of one value in same position in the array, because if you use this code the output of n = 5 and enter value 2 ,2 ,2 ,1,1. the output will be 5 massage box with 3 equal for value 2, and 2 equal for value 1.
you can test by yourself copy the code and insert it to a form in VB.net.
With pictures:
see this link: Picture that describe the result
You can see that the output is more than one for each value, so How can I store the value and its repetition in one position in an array?
Thank you for reading, please I want a code answer. :)

UPDATE
If you want count duplicates(repetitions) of values and then use it for your needs:
Create custom class where you can keep information about value and amount of repetitions
Public Class RepetitionValue
Public Property Value As Single
Public Property RepetitionAmount As Int32
Public Sub New(value As Single)
Me.Value = value
Me.RepetitionAmount = 1
End Sub
End Class
Collect values and count duplicates, save it in then Directory collection
With Directory you will easy get object by value
Use collection for manipulating data
Public Sub YourSybName()
Dim values As New List(Of Single)()
Dim numberOfData As Int32
numberOfData = Int32.Parse(InputBox("How many data?", "RepTest"))
For count As Int32 = 0 To numberOfData - 1
values.Add(InputBox("Add Value", "RepTest"))
Next
Dim modals As New Dictionary(Of Single, RepetitionValue)()
For Each value As Single In values
If modals.ContainsKey(value) = True Then
modals(value).RepetitionAmount += 1
Else
modals.Add(New RepetitionAmount(value))
End If
Next
'Use collection for your needs
'For example if I have 5 data, then I enter 1 . 5 . 1 . 2 . 1.
'then I want to divide repetition of value 1 by repetition of value 5.
Dim valueOf1 As RepetitionValue = modals(1)
Dim valueOf5 As RepetiotionValue = modals(5)
Dim divideResult As Decimal = valueOf1.RepetitionAmount/valueOf5.RepetitionAmount
End Public

Related

Identify missing values from array

I am striving to create a function in VBA that calculates the number of missing values in each column of a matrix of nxn dimensions.
Each column should contain the numbers 1 to n only once.
However if this is not the case I want to the function to state how many values are missing. For example in a column of 4x4 matrix (1,2,1,3) there is one missing value which is 4, and the function should return the value 1, for the 1 missing value.
I am very new to VBA and by no means a master, but this is what I have done so far...
Function calcCost(sol() As Integer, n As Integer) As Integer
Dim ArrayOfTruth(1 To n) As Boolean
For Row = 1 To n
For i = 1 To n
If ProbMatrix(Column, Row) = i Then
ArrayOfTruth(i) = True
cost = 0
For i = 1 To n
If ArrayOfTruth(i) = True Then
cost = cost + 1
Assuming that the requirement of a square range of cells supersedes the description of the 'matrix's' values, I'm not sure why an array is needed at all.
Function calcCost(rTopLeft As Range, n As Long)
Dim c As Long, r As Long
For c = 1 To n
If Not CBool(Application.CountIf(rTopLeft.Resize(n, n), c)) Then _
r = r + 1
Next c
calcCost = r
End Function
Syntax:
    =calcCost(<top left corner of desired range>, <number of cells both right and down>)
Example:
=calcCost(E9, 18)
The above implementation could also be written as,
=18-SUMPRODUCT(--SIGN(COUNTIF(OFFSET(E9,0,0,18,18), ROW(1:18))))

Iterating through the elements in each row of a 2d array (vb.net)

Ok let me explain my question, here I have a 4x4 array of picture boxes which looks like this:
C1 C2 C3 C4
Row 1: [] [] [] []
Row 2: [] [] [] []
Row 3: [] [] [] []
Row 4: [] [] [] []
When the user presses on one of the picture boxes the background color of the picture box changes. I am trying to iterate through each of the rows to figure out which pictures box's have a red background per row. The timer interval is set in Beats Per Minute (60000 / textbox1.text). How do I accomplish this? I made the 2d array but the iteration is not working.
Dim graph(4, 4) As PictureBox
graph(1, 1) = PictureBox1
graph(1, 2) = PictureBox2
graph(1, 3) = PictureBox3
graph(1, 4) = PictureBox4
graph(2, 1) = PictureBox5
graph(2, 2) = PictureBox6
graph(2, 3) = PictureBox7
graph(2, 4) = PictureBox8
graph(3, 1) = PictureBox9
graph(3, 2) = PictureBox10
graph(3, 3) = PictureBox11
graph(3, 4) = PictureBox12
graph(4, 1) = PictureBox13
graph(4, 2) = PictureBox14
graph(4, 3) = PictureBox15
graph(4, 4) = PictureBox16
Private Sub Button5_Click_1(sender As System.Object, e As System.EventArgs) Handles Button5.Click
Dim tempo As Integer = CInt(TextBox1.Text)
Dim BPM As Integer = 60000 / tempo
Timer1.Interval = BPM
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
For i As Integer = 1 To 4
Select Case i
Case 1
For value As Integer = 1 To 4
If graph(1, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 2
For value As Integer = 1 To 4
If graph(2, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 3
For value As Integer = 1 To 4
If graph(3, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 4
For value As Integer = 1 To 4
If graph(4, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case Else
Debug.WriteLine("Not between 1 and 10, inclusive")
End Select
Next
End Sub
Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click
PictureBox1.BackColor = Color.Red
End Sub
Any Help is greatly appreciated. Thank you!
Before I answer your question, here is some general advice regarding your code:
VB array indices are zero-based. An array Dim arr(4) As ... declares an array with five elements (which can be accessed by index 0 through 4). Therefore, your array declaration of graph creates an array with 25 elements when you only need 16. Such waste of memory should be avoided.
The creation of your graph could be automated. It's probably even a better idea to create all picture boxes automatically. This way, if you want to change the graph size, you just have to change a single number instead of a whole bunch of code. Similarly, the bounds of your for loops should respect the actual array bounds instead of some pre-defined constants.
When you parse user input, you should handle incorrect input. Use Integer.TryParse() instead of CInt().
As a beginner, you should turn Option Strict On (via the project settings). This avoids narrowing implicit casts that you might not be aware of. E.g. it would tell you that 60000 / tempo results in a Double and by assigning that to an Integer variable you will loose precision.
I suspect that you have similar click handlers for all picture boxes. If all handlers are doing the same work, use a single handler. The method's sender argument tells you which picture box was clicked (you can cast it to the appropriate type).
Using a For loop does not make any sense if you split the body according to the loop variable. If you do different work in every iteration, don't use a loop at all and just write the code snippets after each other. However, in your case, a loop makes sense, though not as you used it. See next section for more information.
Now to your question. If you want to gather the checked boxes per row, you should use two nested loops. The outer loops iterates the rows and the inner loop iterates columns. Before starting the inner loop, you should reset a buffer that holds the indices of the checked boxes. I use the corrected indices (0 through 3). Furthermore, I assume that the first index in the graph array specifies the row and the second specifies the column. If that's wrong, you just have to swap the according pieces of code:
Dim checkedBoxes As New List(Of Integer) 'holds the indices of checked boxes in a row
For row As Integer = 0 To graph.GetUpperBound(0)
checkedBoxes.Clear()
For col As Integer = 0 To graph.GetUpperBound(1)
...
Next
'Now report the checked boxes.
MessageBox.Show("Checked boxes of row " & row & ":" & Environment.NewLine & _
String.Join(", ", checkedBoxes))
Next
The String.Join method is used to concatenate the list of column indices to a single string, separated by ,.
Now we just need to add code to the loop body that gathers the checked boxes:
If graph(row, col).BackColor = Color.Red Then
checkedBoxes.Add(col)
Next
That's all. No awkward Switch statement, no duplicate code. There are still some improvements that could make this code more efficient, but I'll leave it with this for now.
if you want two message boxes to appear at the same time, the only way would be to run them on different threads, ie after the conditional create a thread that runs the message box to keep the loop going. A message box will halt the code on that thread and waits for user input and the only way you can run 'msgbox()' at the same instant is with multiple threads. Otherwise what you are asking is impossible.

PictureBoxes in an Array

Okay so I've got two problems with this code:
I have 8 picture boxes, I'm trying to run a check on a randomly generated number, to see if it matches the number at the end of the picture box (IE if the random number = 8, another constant gets put into picture box 8 and no other, but only if there isn't already something in it).
I have done it by simply running out every check as a single if statement but... 180 if statements later... that's too much to code.
I'm trying to (as you can see) run it through several while loops. The main part I'm having trouble with is assigning a particular picture box in the array with an image from the array. I can get an image using the imgName and imgPictures(i) using it in the format PictureBox1.Image = imgPictures(i), but not replacing PictureBox1.Image with picBoxes().Image.
Using the MsgBoxes that I've left in the code, the loops and if statements run "Debug1" and "Debug2" but none of the others... Why is this?
I'll leave the code and see what you guys can make of it.
Dim i As Integer = 1
Dim x As Integer = 1
Dim rndnumber As Integer = mathsclass.get_randomnumber()
Dim imgPictures(20) As Image
Dim picBoxes(8) As PictureBox
picBoxes = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4, PictureBox5, PictureBox6, PictureBox7, PictureBox8}
Dim imgName As String = ("_" & i)
imgPictures(0) = My.Resources.ResourceManager.GetObject(imgName)
picBoxes(x).Image = imgPictures(i)
While (i <= 20)
MsgBox("Debug1")
rndnumber = mathsclass.get_randomnumber()
imgName = ("_" & i)
imgPictures(i) = My.Resources.ResourceManager.GetObject(imgName)
x = 0
While (x < 8)
MsgBox("Debug2")
If ((randomnumber = i) & (randomposition = x)) Then
MsgBox("Debug3")
picBoxes(x).Image = imgPictures(i)
Else
While (rndnumber = randomnumber)
MsgBox("Debug4")
rndnumber = mathsclass.get_randomnumber()
End While
MsgBox("Debug5")
If ((randomnumber <> rndnumber) & (randomposition <> x)) Then
MsgBox("Debug6")
imgName = ("_" & rndnumber)
imgPictures(i) = My.Resources.ResourceManager.GetObject(imgName)
picBoxes(x).Image = imgPictures(i)
End If
MsgBox("Debug7")
End If
MsgBox("Debug8")
x += 1
End While
MsgBox("Debug9")
i += 1
End While
Am not really sure which language you are trying to use here. I mean, whether it is VB.Net or class VB6!
I assume it is VisualBasic.Net (VB.Net).
Am not sure whether I understood you clearly. So, am giving you a small example code for you to try it out. The comments in it would pretty much explain I believe.
First create a new blank project. Add 5 textboxes in it(no need to change the names of it. Just drag and drop 5 nos. of textboxes). Add a Button and then double click on it and paste the code that I have shown below:
Dim rand As New Random '~~~ for creating the random numer
Dim intTotal As Integer = 5 '~~~ I have 5 textboxes with the names ending by number from 1 to 5
Dim intUpdated As Integer = 0 '~~~ to store the total number of updated textboxes
'~~~ first of all we are looping through the textboxes(am just showing how you can fetch them via it's name. There are other ways to iterate through the controls though!)
For i As Integer = 1 To intTotal
Dim tbox As TextBox = DirectCast(Me.Controls.Item("TextBox" & i.ToString()), TextBox) '~~~ here, we are fetching the TextBox via it's "Name" property, by appending the number at the end of "TextBox". Because in my form, I have "TextBox1", "TextBox2", "TextBox3", "TextBox4" and "TextBox5"
tbox.Tag = "untouched" '~~~ just setting it's "Tag" property to some text so that we could later use it evaluate whether we have touched this textbox via the random number
'-------------------------------------------------
'if you want to do something else like loading up default text or something, you can do it here too
'-------------------------------------------------
Next
'~~~ the randomly choosing part..
Dim j As Integer = 1
Do While intUpdated < intTotal '~~~ loop until we have taken into consideration all the textboxes via random number
Dim r As Integer = rand.Next(1, intTotal + 1) '~~~ create a random number between 1 and 5 (both inclusive)
'~~~ fetch that TextBox via it's name. Note that, am appending the random number to the name "TextBox". For eg, if the random number generated was "2", it would access "TextBox2"
Dim tbox As TextBox = DirectCast(Me.Controls.Item("TextBox" & r.ToString()), TextBox)
'~~~ since we have textbox now, we are checking whether we have accessed it earlier via random number
If tbox.Tag.ToString() = "untouched" Then '~~~ if not accessed before...
tbox.Tag = "touched" '~~~ mark the textbox as accessed via random number
intUpdated += 1 '~~~ increment the counter variable that we are using for storing the number of textboxes we accessed
'-------------------------------------------------
'~~~ do whatever you want on it here.. Right now, am just inserting some text on it to show the order in which the textboxes are accessed via our random number
tbox.Text = "updated" & j.ToString
j += 1
'-------------------------------------------------
End If
Loop
After running it, I hope you will be able to get the idea. To access a control name residing in your form, you could access it like this: Me.Controls.Item("control_name_goes_here"). So you can append numbers to the string when you mention the control's name. I have used this in code above. Look at it.
BTW, you are using & which is in VB, will act like concatenation operator! ie, Dim a As String = "Akhilesh" & "B Chandran". This will store Akhilesh B Chandran in that variable a. For AND operation, you need to use AND. In C, C++, C#, etc it is && (note that there is two ampersand characters)
Also, in VB.Net, you should use MessageBox.Show() instead of the MsgBox() function. That's the better way.
Hope this will help.

VBA - struggling to calc and write StDev data into an array with a For Next loop

11/24/14 - as per below.....
Still trying to figure this out - might it be easier by creating a smaller array which could roll through the larger array? ...then any necessary calcs could be done on the entirety of the small array.
I cannot figure out how to isolate just a (rolling) subset of an array. The rolling subset could be used for moving averages, standard devs, max/min, etc.
11/21/14 - I have made several attempts, this is the latest iteration. It shouldn't produce meaningful output until the minimum periods have been looped thru (stdev_periods = 10).
--pct_chg_array() is an array which holds percent change data from i=2 to i = 2541... declared as variant
--stdev_periods = 10 ...declared as integer
--i is a counter ...declared as integer
--stdev_array() is an empty array which I hope to populate with a standard deviation calculation for a rolling n period range ...declared as variant
--Option Base 1 and Option Explicit are on
For i = 2 To 2541
If IsNumeric(i) And i <> 0 Then
stdev_array(i, 1) = Application.WorksheetFunction.stdev(Range(pct_chg_array(i, 1).Offset(-stdev_periods, 0), pct_chg_array(i, 0)))
Else
stdev_array(i, 1) = 0
End If
Next i
Any guidance would be immensely appreciated. Thanks!
----EDIT----
Just to simplify, this is how I would express it in a worksheet formula...
=IF(ISNUMBER(OFFSET($E3,-stdev_periods+1,0)),STDEV(OFFSET($E3,0,0,-stdev_periods)),0)
...with "stdev_periods" = 10 and column E holding 1 period %chg data (ie =$E3/$E2-1).
Put this function in the module:
Public Function Slice(vntInputArray As Variant, lngStartIndex As Long, lngEndIndex As Long)
'Use to return an arbitrary-sized subset from a 1 dimensional array.
'Assumes developer is using Option Base 1
Dim vntSubArray() As Variant, lngInputIndex As Long
Dim lngElementCountIndex As Long: lngElementCountIndex = 1
For lngInputIndex = lngStartIndex To lngEndIndex
ReDim Preserve vntSubArray(lngInputIndex)
vntSubArray(lngElementCountIndex) = vntInputArray(lngInputIndex)
lngElementCountIndex = (lngElementCountIndex + 1)
Next lngInputIndex
Slice = vntSubArray
End Function
Adding the function to your code:
For i = 2 To 2541
If IsNumeric(i) And i > stdev_periods Then 'Using greater than to account for Option Base 1
stdev_array(i, 1) = WorksheetFunction.stdev(Slice( pct_chg_array, (i -stdev_periods), i))
Else
stdev_array(i, 1) = 0
End If
Next i

How to compare entire multidimensional arrays? - WinForms VB.NET

How can I compare two entire multidimensional arrays in WinForms VB.NET?
My code is checking to see whether some Subs will change the content of an array.
In order to do this, it makes a carbon copy of the original array before the subs have been executed. This carbon copy is left untouched until after the sub has happened. Once it's done the Sub, I want to see whether anything in the main array has changed. Here's my current code:
If possible = "not possible" Then 'If grid is full
'Check whether something can be done at all
For x = 0 To 5
For y = 0 To 5
copyarray(x, y) = bigarray(x, y)
Next
Next
Dim movementarray() As String = {"up", "down", "left", "right"}
For i = 0 To 3
direction = movementarray(i)
moveblocks()
Next
If copyarray = bigarray Then
'This throws an error
End If
End If
N.B. copyarray is the carbon copy of bigarray; moveblocks() is the Sub which I want to see whether it changes anything; and possible is simply a prerequisite to this code being run.
How do I do this? I ask because Visual Basic throws the following error in respect to the last If statement:
Error 1: Operator '=' is not defined for types '2-dimensional array of Integer' and '2-dimensional array of Integer'. Use 'Is' operator to compare two reference types. My Game\Form1.vb Line 282 Character 16 My Program
Ok, I solved it. Here's my solution:
Private Function whatever() as Boolean
If possible = "not possible" Then 'If grid is full
'Check whether something can be done at all
For x = 0 To 5
For y = 0 To 5
copyarray(x, y) = bigarray(x, y)
Next
Next
Dim movementarray() As String = {"up", "down", "left", "right"}
For i = 0 To 3
direction = movementarray(i)
moveblocks()
Next
Dim changed as Boolean = False
For i = 0 to 5
For j = 0 to 5
If Not copyarray(i, j) = bigarray(i, j) Then Return True : Exit Function
Next
Next
Return False
End If
Return False
End Function

Resources