How to loop through Two arrays in TWO FOR Each loop - arrays

There are two FOR EACH loops in the code below. The first FOR loop cycles through the first array (shape 1,shape 2 ,shape 3).The second FOR loop cycles through the second array (0.3, 0.4, 0.5).
Shape 1 0.3
Shape 2 0.4
Shape 3 0.5
The second FOR loop colors the shape on my worksheet based on the value of second array. The problem is all of my shapes are being colored with first value (i.e 0.3). I want Shape 1 to be colored based on 0.3 , Shape 2 based on 0.4 and so on. Thanks for helping me with this.
Private Sub Worksheet_Calculate()
Dim arr1
Dim arr2
Set arr1 = Worksheets("Sheet2").Range("valueforarr1")
Set arr2 = Worksheets("Sheet2").Range("Valueforarr2")
Dim c, d As Range
For Each c In arr1
c = Replace(c, " ", "_")
MsgBox c
For Each d In arr2
If d >= 0.2 And d <= 0.3 Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(237, 247, 249)
Exit For
ElseIf d > 0.3 And d <= 0.4 Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(218, 238, 243)
Exit For
ElseIf d > 0.4 And d <= 0.5 Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(183, 222, 232)
Exit For
ElseIf d > 0.5 Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(146, 205, 220)
Exit For
ElseIf d Is Nothing Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(255, 255, 255)
Exit For
End If
Next d
Next c
End Sub

Hmm.. i guess your Problem is the second loop.
You take the First Shape and match it with all Values of the second Range-loop
What your loops are doing is:
Shape 1 -> 0.3
Shape 1 -> 0.4
Shape 1 -> 0.5
than the same with Shape 2
Shape 2 -> 0.3
Shape 2 -> 0.4 etc.
So if im Right its always the last Value of Range2
Dim intRow As Integer
intRow = 1
For Each c In arr1
c = Replace(c, " ", "_")
MsgBox c
If Worksheets("Sheet1").Cells(intRow,2).value = "0.3" Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(237, 247, 249)
Exit For
If Worksheets("Sheet1").Cells(intRow,2).value = "0.4" Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(237, 247, 249)
Exit For
If Worksheets("Sheet1").Cells(intRow,2).value = "0.5" Then
Worksheets("Sheet1").Shapes(c).Fill.ForeColor.RGB = RGB(237, 247, 249)
Exit For
intRow=intRow+1
Next c

I think this will do what you need. You will need to change the Set myShapes = ... and Set myValues = ... lines to point to your ranges.
Sub Worksheet_Calculate()
Dim myShapes As Range
Set myShapes = Worksheets("Sheet1").Range("A1:A5")
Dim myValues As Range
Set myValues = Worksheets("Sheet1").Range("B1:B5")
For i = 1 To myShapes.Rows.Count
Select Case myValues.Rows(i)
Case Is = 0.3
Worksheets("Sheet1").shapes(myShapes(i)).Fill.ForeColor.RGB = RGB(237, 247, 249)
Case Is = 0.4
Worksheets("Sheet1").shapes(myShapes(i)).Fill.ForeColor.RGB = RGB(218, 238, 243)
Case Is = 0.5
Worksheets("Sheet1").shapes(myShapes(i)).Fill.ForeColor.RGB = RGB(183, 222, 232)
Case Is > 0.5
Worksheets("Sheet1").shapes(myShapes(i)).Fill.ForeColor.RGB = RGB(146, 205, 220)
Case Else
Worksheets("Sheet1").shapes(myShapes(i)).Fill.ForeColor.RGB = RGB(255, 255, 255)
End Select
Next i
End Sub
One note:
What you are calling arrays (arr1, arr2) are actually Range objects.

Related

How to assign an array's values to a range?

I'm trying to assign a 1-dimensional array's values to cell range.
For example; my array has 23 items (every item randomized from 1 to 5) and my cell range is range A1 to I7.
I want to assign every value of my array to this cell range randomly.
I randomize the cell values with my array but my array's values are not completely assigned to cells.
Sub define_ore_body()
Dim lb_grade As Integer, ub_grade As Integer
Dim ore_body(1 To 23) As Variant
Dim i As Integer, j As Integer, k As Integer
Dim a As Object
Dim b As Range
Application.ScreenUpdating = False
'my selected range area A1toI7
Set b = Application.Range("A1:I7")
Set a = Application.Cells
'******* low and high ore bound ******
lb_grade = InputBox("Enter lowest ore grade:")
ub_grade = InputBox("Enter highest ore grade:")
'The reason why I do it as follows is that if the random lower bound does not start from 1,
'the largest random number it generates is 2 more than the value I have entered, so
If lb_grade > 1 Then
ub_grade = ub_grade - 2
End If
'******* Random Array ******
'array has 23 items
For i = 1 To 23
ore_body(i) = Int((ub_grade * Rnd) + lb_grade)
Next i
'******* filling random cells with my array******
k = 1
For Each a In b
If a.Value = "" And k < 23 Then
b(Int(7 * Rnd + 1), (8 * Rnd + 1)) = ore_body(k)
ElseIf a.Count > 23 And k > 23 Then
Exit For
Else
k = k + 1
End If
Next a
'******* after filling cell now fill empty cells with Zero******
For i = 1 To 7
For j = 1 To 9
If Cells(i, j) = "" Then
Cells(i, j) = 0
Else
End If
Next j
Next i
'******* Coloring only containing array values******
For i = 1 To 7
For j = 1 To 9
If Cells(i, j) > 0 Then
Application.Cells(i, j).Interior.ColorIndex = 38
Else
End If
Next j
Next i
End Sub
The array contains 23 items that initialize to Variant/Empty:
Dim ore_body(1 To 23) As Variant
Make that 63 items that initialize to 0:
Dim ore_body(1 To 63) As Long
The rest of the code will now populate the first 23 elements, because that's what the loop does:
For i = 1 To 23
If you want the loop to run through all indexes, consider using LBound and UBound operators to programmatically retrieve the lower and upper boundaries of the array, respectively:
For i = LBound(ore_body) To UBound(ore_body)
Note that you have 23 hard-coded in several places, which is going to make it harder than necessary to modify if/when that 23 needs to be come a 25. Consider replacing every occurrence of it by a Const:
Const ElementCount As Long = 23
Then every instance of 23 can become ElementCount, and then when it needs to become 25 then there's only one place that needs any code to change.
Loop through the array.
Set a to a random cell in the range A1:I7.
If cell is empty put the value from the array in the cell, if it
isn't repeat step 2
Sub define_ore_body()
Dim lb_grade As Integer, ub_grade As Integer
Dim ore_body(1 To 23) As Variant
Dim i As Long, j As Long, k As Long
Dim a As Range
Dim b As Range
Application.ScreenUpdating = False
'my selected range area A1:I7
Set b = Application.Range("A1:I7")
' clear A1:A17
b.Clear
'******* low and high ore bound ******
lb_grade = InputBox("Enter lowest ore grade:")
ub_grade = InputBox("Enter highest ore grade:")
'The reason why I do it as follows is that if the random lower bound does not start from 1,
'the largest random number it generates is 2 more than the value I have entered, so
If lb_grade > 1 Then
ub_grade = ub_grade - 2
End If
'******* Random Array ******
'array has 23 items
For i = 1 To 23
ore_body(i) = Int((ub_grade * Rnd) + lb_grade)
Next i
'******* filling random cells with my array******
For k = 1 To 23
Do
Set a = b.Cells(Int(7 * Rnd) + 1, Int(9 * Rnd) + 1)
Loop Until a.Value = ""
a.Value = ore_body(k)
Next k
'******* after filling cell now fill empty cells with Zero******
For i = 1 To 7
For j = 1 To 9
If Cells(i, j) = "" Then
Cells(i, j) = 0
Else
End If
Next j
Next i
'******* Coloring only containing array values******
For i = 1 To 7
For j = 1 To 9
If Cells(i, j) > 0 Then
Application.Cells(i, j).Interior.ColorIndex = 38
Else
End If
Next j
Next i
End Sub

vba loop through array, store values to arrayi

I have some data, stored in arrays like
Dim arrA, arrB, arrC, arrAi, arrBi
Dim i as integer, x as integer
for i = 1 to 100
if cells(i,1).value = "criteria" then ' just add value to array when it meets some criteria
x = x + 1
arrA(x) = cells(i,1).value
arrB(x) = cells(i,2).value
arrC(x) = cells(i,3).value
end if
next i
redim preserve arrA(1 to x)
redim preserve arrB(1 to x)
redim preserve arrC(1 to x)
And the data looks like
arrA: 26.1 40.2 80.3 26.0 41.3 78.7 25.8 40.8 80.0
arrB: 10 11 10 66 67 64 32 32 33
arrC: 1 2 3 1 2 3 1 2 3
Since the values in arrA 26.1, 26.0, 25.8 (position 1, 4, 7) belong to group 1 (referencing to values in arrC at same position), I would like to store 26.1 26.0 25.8 to arrAi and 10 66 32 to arrBi for subsequent calculations.
How can I loop through the 3 arrays and store values to another array as described above?
Thanks in advance.
Try the next way, please:
Sub handleArraysFromArrays()
'your existing code...
'but you fistly must declare
Dim arrA(1 To 100), arrB(1 To 100), arrC(1 To 100)
'....
'your existing code
'...
Dim k As Long, kk As Long
ReDim arrAi(1 To UBound(arrA))
ReDim arrBi(1 To UBound(arrA))
For i = 1 To UBound(arrC)
If arrC(i, 1) = 1 Then k = k + 1: arrAi(k, 1) = arrA(i, 1)
If arrC(i, 1) = 2 Then kk = kk + 1: arrBi(kk, 1) = arrA(i, 1)
Next i
ReDim Preserve arrAi(1 To k): ReDim Preserve arrBi(1 To kk)
Debug.Print UBound(arrAi), UBound(arrBi)
End Sub

Using a sub to call an array within a function

I have a little problem with my sub. This sub is calling to different functions, by using the sub's data. The first function finds one is finding the amount of unique values and the second function finds these values. However, the first function works fine because its output is a scalar value. However, the second function's output is an array. I have tried to search for a solution, but so far I have not succeeded. I have a theory that the issue has something to do with the ByRef A() As Integer. I have written the codes below, both for the sub and the second function.
Sub Test()
Dim A() As Integer
Dim n As Integer
Dim BB As Integer
n = 10
ReDim A(n, 2) '5 unikke
A(1, 1) = 1
A(2, 1) = 7
A(3, 1) = 2
A(4, 1) = 6
A(5, 1) = 3
A(6, 1) = 5
A(7, 1) = 1
A(8, 1) = 1
A(9, 1) = 1
A(10, 1) = 4
A(1, 2) = 1
A(2, 2) = 7
A(3, 2) = 2
A(4, 2) = 6
A(5, 2) = 3
A(6, 2) = 5
A(7, 2) = 1
A(8, 2) = 1
A(9, 2) = 1
A(10, 2) = 4
BB = Unikke(A) 'Unikke is the second function that provides the amount of unique values
Dim FF() As Integer
ReDim FF(BB, 1)
FF = HvilkeUnikke(A) 'the second function, which has the output of an array a.k.a the problem
End Sub
This is the function:
Public Function HvilkeUnikke(ByRef A() As Integer) As Integer
Dim L() As Integer
Dim B As Integer
Dim i As Integer
Dim i2 As Integer
Dim A2() As String
Dim BB As Integer
Dim C() As Integer
BB = Unikke(A)
ReDim C(UBound(A), 2)
ReDim A2(BB, 1)
ReDim L(BB, 1)
For i = 1 To UBound(A)
C(i, 1) = A(i, 1)
C(i, 2) = A(i, 2)
Next
For i = 1 To UBound(C)
B = 0
For i2 = 1 To UBound(C)
If C(i, 1) = C(i2, 2) Then
B = B + 1
If B > 1 Then
C(i2, 2) = 0
End If
End If
Next i2
Next i
B = 0
For i2 = 1 To UBound(C)
If C(i2, 2) > 0 Then
B = B + 1
L(B, 1) = C(i2, 2)
End If
Next i2
HvilkeUnikke = L
End Function
The results are as expected, but they should be in a variable inside my sub.
(The solution)
Sub test()
Dim FF() As Integer
Dim i As Integer
Dim A() As Integer
Dim n As Integer
Dim BB As Integer
n = 10
ReDim A(n, 2) '7 unikke
A(1, 1) = 1
A(2, 1) = 7
A(3, 1) = 2
A(4, 1) = 6
A(5, 1) = 3
A(6, 1) = 5
A(7, 1) = 1
A(8, 1) = 1
A(9, 1) = 1
A(10, 1) = 4
A(1, 2) = 1
A(2, 2) = 7
A(3, 2) = 2
A(4, 2) = 6
A(5, 2) = 3
A(6, 2) = 5
A(7, 2) = 1
A(8, 2) = 1
A(9, 2) = 1
A(10, 2) = 4
BB = Unikke(A)
ReDim FF(BB)
FF = HvilkeUnikke(A)
'Testing on the worksheet
For i = 1 To BB
Cells(i, 1) = FF(i)
Next
End Sub
And the function
Public Function HvilkeUnikke(ByRef A() As Integer) As Integer()
Dim L() As Integer
Dim B As Integer
Dim i As Integer
Dim i2 As Integer
Dim A2() As String
Dim BB As Integer
Dim C() As Integer
BB = Unikke(A)
ReDim C(UBound(A), 2)
ReDim A2(BB, 1)
ReDim L(BB)
For i = 1 To UBound(A)
C(i, 1) = A(i, 1)
C(i, 2) = A(i, 2)
Next
For i = 1 To UBound(C)
B = 0
For i2 = 1 To UBound(C)
If C(i, 1) = C(i2, 2) Then
B = B + 1
If B > 1 Then
C(i2, 2) = 0
End If
End If
Next i2
Next i
B = 0
For i2 = 1 To UBound(C)
If C(i2, 2) > 0 Then
B = B + 1
L(B) = C(i2, 2)
End If
Next i2
HvilkeUnikke = L
End Function

Running 6 Month Sum for Each Value of an Array

I am trying to calculate a 6 month running sum of "Points" for each badge number. The sum only applies to fields with points greater than 0.
I have been trying to do this using an array and a For statement, but I'm not getting anywhere.
Sub TestArray()
'
'
'
' Test Array Macro
Dim Badges() As Long
Dim Badge As Variant
Dim i As Long
Dim x As Double
Dim Worksheet1 As Worksheet
Dim AbsCode As Long
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ActiveSheet
'Using Find Function
LastRow = sht.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
Set Worksheet1 = ActiveWorkbook.Worksheets("Attendance Data") ' Change name of sheet if necessary
BadgeNo = 1
AbsCode = 3
Hours = 5
Points = 9
Rules = 10
test = 15
ReDim Badges(2 To LastRow, 1 To 1)
For Each Badge In Badges
For i = 2 To LastRow
If Worksheet1.Cells(i, Points).Value > 0 Then
Worksheet1.Cells(i, test).Value = Application.WorksheetFunction.Sum(Worksheet1.Cells(i, Points).Value)
Else: Worksheet1.Cells(i, test).Value = 0
End If
Next i
Next Name
End Sub
The answer that I'm looking for is in the "6 Month Points" column below.
Badge No. Incident Date Points 6 Month Points
30004832 1/13/2018 0.5 0.5
30004832 1/27/2018 0.0 0
30004832 4/5/2018 1.0 1.5
30004832 7/19/2018 0.0 0
30004832 7/22/2018 0.5 1.5
30004832 9/22/2018 1.0 2.5
30005505 8/4/2018 0.5 0.5
30005505 12/6/2018 0.5 1
30005914 12/20/2018 0.0 0
30004641 1/18/2018 0.5 0.5
30004641 2/2/2018 0.5 1
30004641 7/17/2018 0.0 0
30004641 10/16/2018 0.0 0
30000503 4/12/2012 0.0 0
30000503 5/3/2012 0.0 0
30000503 6/14/2012 0.0 0

Input/output values into an array

EDIT: Updated question using some of the suggestions below. This produces weird output though.
Dim ProviderArray() As Variant
Sub GetProviderNumbers()
Dim InputRange As Range
Dim WorkRange As Range
Set InputRange = Range("ProviderList")
Set WorkRange = Application.Intersect(InputRange, ActiveSheet.UsedRange)
SizeOfArray = Application.WorksheetFunction.CountA(WorkRange)
ReDim ProviderArray(0 To SizeOfArray)
ProviderArray = WorkRange.Value
For r = 1 To UBound(ProviderArray, 1)
For C = 1 To UBound(ProviderArray, 2)
Debug.Print r, C, ProviderArray(r, C)
Next C
Next r
End Sub
1 1 5555
2 1 4444654
3 1 654654
4 1 654654654
5 1
6 1
7 1
8 1
9 1
10 1
11 1
12 1
13 1
14 1
15 1
16 1
17 1
18 1
19 1
Could someone explain why this output?
You can only use the one-line approach if you put the range into a 2-D array: you only have a 1-D array.
You could do this:
Dim ProviderArray()
Set WorkRange = .Intersect(InputRange, ActiveSheet.UsedRange)
'This makes ProviderArray a 2-D array, dimension 1 = # rows,
' dimension2 = #cols. Both dimensions are 1-based.
ProviderArray = WorkRange.value
for r=1 to ubound(ProviderArray,1)
for c=1 to ubound(ProviderArray,2)
debug.print r,c,ProviderArray(r,c)
next c
next r
Maybe something a bit simpler like:
Private Sub GetProviderNumbers()
Dim InputRange() As Variant
InputRange = Range("ProviderList")
For Each i In InputRange
Debug.Print i
Next
End Sub
This captures a two-dimensional range and stores the values in a global two-dimensional array:
Dim ProviderArray() As String
Sub MAIN()
Range("B2:C11").Name = "ProviderList"
Call GetProviderNumbers
End Sub
Sub GetProviderNumbers()
ary = Range("Providerlist")
ll = LBound(ary, 1)
lm = LBound(ary, 2)
ul = UBound(ary, 1)
um = UBound(ary, 2)
ReDim ProviderArray(ll To ul, lm To um)
For i = ll To ul
For j = lm To um
ProviderArray(i, j) = ary(i, j)
Next
Next
End Sub

Resources