VBA: How to call an Userform Object by its name (Loop) - excel

I just started to learn VBA for a project and i have a userform where i have multiple sliders that give me values that i want to use to build a 2D Array with For loops.
My Array is 5 by 5 and it is "Symmetric" (1 as diagonal, Thus I only need one side for the values).
I obtain the matrix values after converting values obtained from sliders in the GUI, which i named Sld1v2 (for row 1, col 2), Sld1v3 (for row1, col3) etccc.
I am thus looking for a way to call the right Slider (by its custom name) in the for loops but i cannot figure how i can do it, can you help me ? I currently have a Type Error, when running the line --> JudgementMatrix(lig,col) = JudgementVector(....)
Following you can see the Excel Version of what i want to code and my attempt of a script.
I hope my request is clear :)
EDIT: By changing Variant type to Double for the Matrix and Vector (since i saw my vector had different types within). I now get an error when i call the function Array. But the thing is that Array returns a variant! --> Filled the Vector manually
Screenshot of the Excel of what i want to code
Dim JudgementVector(16) As Double
Dim JudgementMatrix(4, 4) As Double
Dim lig As Integer
Dim col As Integer
For i = 0 To 16
If i < 8 Then
JudgementVector(i) = (1 / (9 - i))
Else
If i >= 8 Then
JudgementVector(i) = i - 7
End If
End If
Next i
For lig = 0 To 4
For col = 0 To 4
If col = lig Then
JudgementMatrix(lig, col) = 1
Else
If col > lig Then
JudgementMatrix(lig, col) = JudgementVector(UserForm1.Controls(["sld"&lig&"v"&col]).Value + 8)
Else
If lig > col Then
JudgementMatrix(lig, col) = 1 / JudgementMatrix(col, lig)
End If
End If
End If
Next col
Next lig

Apparently it didnt like having "Text" & variable & "Text" & Variable
so i by passed it by creating temp values to combine step by step.
Dim JudgementVector(16) As Double
Dim JudgementMatrix(4, 4) As Double
Dim lig As Integer
Dim col As Integer
Dim Temp1 As String
Dim Temp2 As String
Dim Temp3 As String
' JudgementVector = ([{1 / 9, 1 / 8, 1 / 7, 1 / 6, 1 / 5, 1 / 4, 1 / 3, 1 / 2, 1, 2, 3, 4, 5, 6, 7, 8, 9}])
For i = 0 To 16
If i < 8 Then
JudgementVector(i) = (1 / (9 - i))
Else
If i >= 8 Then
JudgementVector(i) = i - 7
End If
End If
Next i
For lig = 0 To 4
For col = 0 To 4
If col = lig Then
JudgementMatrix(lig, col) = 1
Else
If col > lig Then
Temp1 = "sld" & lig + 1
Temp2 = "v" & col + 1
Temp3 = Temp1 & Temp2
JudgementMatrix(lig, col) = JudgementVector(UserForm1.Controls(Temp3) + 8)
Else
If lig > col Then
JudgementMatrix(lig, col) = 1 / JudgementMatrix(col, lig)
End If
End If
End If
Next col
Next lig

Related

Randomizing specific position of numbers

For example, I have numbers 1,9,7,4 and I want to randomize their position so I will get 9,1,4,7 or 7,1,9,4 etc. Do you know how? Thanks
Here is a basic vba randomize into a dictionary object.
Dim vals As Variant, ord As Object
Set ord = CreateObject("scripting.dictionary")
vals = Array(1, 4, 7, 9)
Do While ord.Count < (UBound(vals) + 1)
ord.Item(vals(Application.RandBetween(LBound(vals), UBound(vals)))) = vbNullString
Loop
Debug.Print Join(ord.keys, ", ")
Here's a more likely (simplistic) example: (I hope I didn't do your homework for you)
Sub sub1()
Dim i1&, i2&, iswap&, a4 As Variant
a4 = Array(1, 9, 7, 4)
For i1 = 0 To 3
i2 = Int(Rnd() * 4) ' random integer 0 to 3
iswap = a4(i1) ' swap(a4(i1), a4(i2))
a4(i1) = a4(i2)
a4(i2) = iswap
Next i1
Debug.Print a4(0); a4(1); a4(2); a4(3) ' Ctl-G to view, F7 to get back to code
End Sub
You didn't specify the basic dialect so here is some code:
a(1) = 1 : a(2) = 4 : a(3) = 7 : a(4) = 9
FOR l = 1 TO 4
SWAP a(l), a(INT(RND * 4 + 1))
NEXT
END

Integer makes Array return wrong value

I defined the following Array:
Global Locations_Array() As String
ThisWorkbook.Worksheets("Locations").Activate
TotalRowsLocations = ActiveSheet.UsedRange.Rows.Count
ReDim Locations_Array(1 To TotalRowsLocations, 1 To 6) As String
According to this I expect the first row of the array to be row 1.
I used this array to name new worksheets in my workbook, and that started at 1, and ended where it should.
However now I call again on this array with the following code:
Sub Get_Lat_Lng()
Dim row As Integer
Dim data_row As Integer
Call Fill_Array_Locations
totalrowsdata = ThisWorkbook.Worksheets("Locations").UsedRange.Rows.Count - 1
TotalRowsDataLookup = ThisWorkbook.Worksheets(Locations_Array(row, 1)).UsedRange.Rows.Count
For row = 2 To totalrowsdata
ThisWorkbook.Worksheets(Locations_Array(row, 1)).Activate
If (UCase(Locations_Array(row, 5))) = (UCase(ThisWorkbook.ActiveSheet(row, 7))) And (UCase(Locations_Array(row, 6))) = (UCase(Worksheet.ActiveSheet(row, 8))) Then
For data_row = 1 To TotalRowsDataLookup
If (UCase(Locations_Array(row, 2)) = UCase(ThisWorkbook.Worksheets(Locations_Array(data_row, 1)).Cells(data_row, 5))) Then
Cells(data_row, 7) = Locations_Array(row, 5)
Cells(data_row, 8) = Locations_Array(row, 6)
Exit For
End If
Next data_row
Exit For
End If
Next row
End Sub
And it returns an "Run-time error '9': Subscript out of range"
When I check for the values in this line of code row has the value of 0 due to being an Integer. Is there a way to make this Integer start at 1 instead of 0? I found the option to set :
Option Base 1
But this interferes with the rest of my code.
Defining an integer for Dim row As Integer withough assigning a value to it will default to row = 0. If you want a different value then you must assign the value you want to it before you use it.
Try:
Dim row As Integer
row = 1
Provided yo uhave data in each row of your Location_Array up to totalrowsdata then your For Loop will redefine row = 2 as the starting value and increment up to totalrowsdata.
The best way to understand the effect the change will have on your code is to try it and see. If it doesn't work as you think, try using F8 to step through each line and check the value of row with each loop.
Sub Get_Lat_Lng()
Dim row As Integer
Dim data_row As Integer
Call Fill_Array_Locations
totalrowsdata = ThisWorkbook.Worksheets("Locations").UsedRange.Rows.Count - 1
Row = 1 'Row should be at least 1
'"Row" should be at least 1 before here.
TotalRowsDataLookup = ThisWorkbook.Worksheets(Locations_Array(row, 1)).UsedRange.Rows.Count
For row = 2 To totalrowsdata
ThisWorkbook.Worksheets(Locations_Array(row, 1)).Activate
If (UCase(Locations_Array(row, 5))) = (UCase(ThisWorkbook.ActiveSheet(row, 7))) And (UCase(Locations_Array(row, 6))) = (UCase(Worksheet.ActiveSheet(row, 8))) Then
For data_row = 1 To TotalRowsDataLookup
If (UCase(Locations_Array(row, 2)) = UCase(ThisWorkbook.Worksheets(Locations_Array(data_row, 1)).Cells(data_row, 5))) Then
Cells(data_row, 7) = Locations_Array(row, 5)
Cells(data_row, 8) = Locations_Array(row, 6)
Exit For
End If
Next data_row
Exit For
End If
Next row
End Sub

Auto down to next row if mod 3 = 0

I try to write code to insert value in a range have 3 column and row based on array of values. I need to insert value from 1 to 1000 to my range as 1,2,3 next row, 4,5,6 next row, 7,8,9 next row until 1000.
Please someone help me, I have tried to find in stackoverflow but no result match
Try this:
Sub test2()
Dim i As Integer, r As Integer
r = 1
For i = 1 To 1000
If i Mod 3 = 0 Then
Cells(r, 3) = i: r = r + 1
Else
Cells(r, i Mod 3) = i
End If
Next i
End Sub
If you are about Excel;
If first row is 1 :
Col1 = (ROW() - 1) * 3 + 1,
Col2 = (Row() - 1) * 3 + 2,
Col3 = (ROW() - 1) * 3 + 3
Else : #fr = row number of first row :
Col1 = (ROW() - #fr) * 3 + 1,
Col2 = (ROW() - #fr) * 3 + 2,
Col3 = (ROW() - #fr) * 3 + 3
A Better Way is use This : (#fr = 1 if first row is 1)
=(ROW() - #fr) * 3 + COLUMN()
In VBA add this:
Public Function myFunc(row as integer, col as integer, Optional fr As Integer = 1) As Integer
myFunc = (row - fr) * 3 + Col + 1
End Function
Then use it.
For you:
Sub test2()
Dim i As Integer, row As Integer, col As Integer
a = 1
For i = 1 To 1000
row = (i - 1) \ 3 + 1
col = (i - 1) mod 3 + 1
Cells(row, col) = myfunc(row, col)
Next i
End Sub

Excel Function to repeat a set of cells for a certain number of times based on cell value

I am looking for a way to repeat a set of cells horizontally a certain number of times before moving on to the next set of cells. For example:
If I have this in 3 columns:
5 4 3
0 1 2
and I have 3 columns which dictate how many times I want the values iterated:
4 2 3
This function should give me this when dragged over a range:
5 5 5 5 4 4 3 3 3
0 0 0 0 1 1 2 2 2
Does anyone know the best manner to do this?
I have been using some convoluted reasoning to get through this with an array formula ( has the "{}" brackets around it and you have to use Shift+Enter). I am using SUMIF and COUNTIF functions to do some things, but it never really works out.
Here's a hacky VBA solution. This assumes the "repeat counts" are on the first row (4, 2, 3) and the "values to repeat" are on the second row (5, 4, 3, 0, 1, 2).
Sub outputRepeatedValues()
Dim xStart As Integer, yStart As Integer
Dim i As Integer, j As Integer
Dim valueToRepeat As Integer, numTimesRepeat As Integer
Dim xOffset As Integer, yOffset As Integer
xStart = ActiveCell.Column
yStart = ActiveCell.Row
i = 1
j = 1
xOffset = 0
yOffset = 0
While Cells(2, j) <> ""
If Cells(1, i) = "" Then
i = 1
yOffset = yOffset + 1
xOffset = 0
End If
numTimesRepeat = Cells(1, i)
valueToRepeat = Cells(2, j)
For k = 1 To numTimesRepeat
Cells(yStart + yOffset, xStart + xOffset) = valueToRepeat
xOffset = xOffset + 1
Next k
j = j + 1
i = i + 1
Wend
End Sub
Stick this in a new module. To use this code, select the cell representing the upper left corner of the output region. Then press Alt+F8 to bring up the Macro box, and then you can run the macro.

Find every combination of cells in a column where the sum is a specific value

If given a column of data in Excel, for example:
2
5
8
10
3
6
Is it possible to check the column to find every all combinations where they meet a specific criteria? In this example when and the sum of any combination of those values is equal to 8.
The values it should find would be
2
5
8
3
6
As 2+6, 5+3, 8 all equal 8
It's my understanding that I am basically asking to check the following
if 2 = 8 or
if 5 = 8 or
if 8 = 8 or
if 10 = 8 or
if 3 = 8 or
if 6 = 8 or
if 2+5 = 8 or
if 2+8 = 8 or
if 2+10 = 8 or
if 2+3 = 8 or
if 2+6 = 8 or
etc
I have only used simple numbers to try and give an example. I'm fairly certain this is not possible.
Try the below code. You have to enter the values to match in column A and the results will show up in column B. I was able to achive a two way match and a three way match. if you wan Can do it till 5 way match after it will become more complex.
Sub Testing()
Dim RowNumber As Double
Dim Temp1 As Double
Dim Temp2 As Double
Dim Temp3 As Double
Dim Result As Double
Dim MatchCount As Double
'Value to be searched
Result = Application.InputBox("Please insert a Number", "Combi Calculator", "", , , , , 1)
'get the last row
RowNumber = Sheet1.Range("A1048576").End(xlUp).Row
'set matchcount to
MatchCount = 1
'Two way match
For Temp1 = 2 To RowNumber
For Temp2 = 3 To RowNumber
If Cells(Temp1, 2) = "" And Cells(Temp2, 2) = "" Then
If Cells(Temp1, 1) + Cells(Temp2, 1) = Result Then
Cells(Temp1, 2) = MatchCount
Cells(Temp2, 2) = MatchCount
MatchCount = MatchCount + 1
End If
End If
Next
Next
'Three way match
For Temp1 = 2 To RowNumber
For Temp2 = 3 To RowNumber
For Temp3 = 4 To RowNumber
If Cells(Temp1, 2) = "" And Cells(Temp2, 2) = "" And Cells(Temp3, 2) = "" And Temp1 <> Temp2 And Temp2 <> Temp3 And Temp1 <> Temp3 Then
If Cells(Temp1, 1) + Cells(Temp2, 1) + Cells(Temp3, 1) = Result Then
Cells(Temp1, 2) = MatchCount
Cells(Temp2, 2) = MatchCount
Cells(Temp3, 2) = MatchCount
MatchCount = MatchCount + 1
End If
End If
Next
Next
Next
End Sub
I am not sure how to send a excel file as an attachement as I am new to this page.
meanwhile let me reseach time topic a bit more. This was always area I wanted to work in (i.e., logic).
A two-way match is very simple using COUNTIF. If your number range is in column A and you want to find two numbers in the range that sum to 72, enter this formula in B1 and copy it down to B20:
=COUNTIF($A$1:$A$20,72-A1)

Resources