How easy compare value of incremented const? - arrays

There are several constants TAX1, TAX2, TAX3,...,TAX_y Further array (arrSorted) of data, prices,..
I need compare value arrSorted(allRow, 8) with TAX and make some sums.
But how increment end number of constant TAX?
for i = LBound... to UBound...
for y = 1 to 5
if arrSorted(i,8) = TAX & y then 'i dont know how TAX & y...
' SUMS HERE
end if
next y
next i
I now have this recurring code (That's not very nice):
Function prepareData(arrSorted() As Variant)
Dim qi As Integer
Dim qy As Integer
Dim sumPrice(0 To 4, 0 To 5) As Variant
For qi = LBound(arrSorted(), 1) To UBound(arrSorted(), 1)
Select Case arrSorted(qi, 8)
Case Is = TAX1
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(0, qy) = sumPrice(0, qy) + arrSorted(qi, qy + 4)
Next qy
Case Is = TAX2
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(1, qy) = sumPrice(1, qy) + arrSorted(qi, qy + 4)
Next qy
Case Is = TAX3
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(2, qy) = sumPrice(2, qy) + arrSorted(qi, qy + 4)
Next qy
Case Is = TAX4
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(3, qy) = sumPrice(3, qy) + arrSorted(qi, qy + 4)
Next qy
Case Is = TAX5
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(4, qy) = sumPrice(4, qy) + arrSorted(qi, qy + 4)
Next qy
Case Else
MsgBox "Alert!", vbCritical
End Select
Next qi
End Function

You cant dynamically adjust variable names inside the code module during code execution.
But what you can do is put all your constants into an array and loop through the array of constants until you find the one you're looking for.
Or you could put all the constants into a dictionary with their variable name as the key. So MyDictionary("TAX1") = TAX1 is true. In your code you could do If arrSorted(i,8) = MyDictionary("TAX" & y).
Here's an example of how to create a dictionary object:
Dim MyDictionary As Object
Set MyDictionary = CreateObject("Scripting.Dictionary")
'Putting the constants inside with their variable name as the key
MyDictionary.Add Key:="TAX1", Item:=TAX1
MyDictionary.Add Key:="TAX2", Item:=TAX2
MyDictionary.Add Key:="TAX3", Item:=TAX3
MyDictionary.Add Key:="TAX4", Item:=TAX4
MyDictionary.Add Key:="TAX5", Item:=TAX5
MyDictionary.Add Key:="TAX6", Item:=TAX6
MyDictionary.Add Key:="TAX7", Item:=TAX7
MyDictionary.Add Key:="TAX8", Item:=TAX8
'How to retrieve their values
MsgBox MyDictionary("TAX8")

Use a dictionary and the exists method in place of Select Case.
Function prepareData(arrSorted() As Variant)
Const TAX1 = 5
Const TAX2 = 10
Const TAX3 = 15
Const TAX4 = 20
Const TAX5 = 25
Dim qi As Integer, qy As Integer, key As String, i As Integer
Dim sumPrice(0 To 4, 0 To 5) As Variant
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add CStr(TAX1), 0
dict.Add CStr(TAX2), 1
dict.Add CStr(TAX3), 2
dict.Add CStr(TAX4), 3
dict.Add CStr(TAX5), 4
For qi = LBound(arrSorted(), 1) To UBound(arrSorted(), 1)
key = Trim(arrSorted(qi, 8))
If dict.exists(key) Then
i = dict(key)
For qy = LBound(sumPrice, 2) To UBound(sumPrice, 2)
sumPrice(i, qy) = sumPrice(i, qy) + arrSorted(qi, qy + 4)
Next qy
Else
MsgBox "Alert! Row " & qi, vbCritical, "Value=" & key
End If
Next qi
' result
Sheet2.Range("A1:F5").Value2 = sumPrice
End Function

Related

The loop over two arrays take LONG

Thanks for your helps,
I have two arrays: A (100k row, 10 col) and B (100k row, 12 col)
The following code (thanks to BSALV) loop through A and B => It takes really long to finish. Is there any way to speedup.
ReDim Preserve B(1 To UBound(B), 1 To UBound(B, 2) + 4)
ReDim arr(1 To UBound(B), 1 To 2)
For i = 1 To UBound(B)
iSell = B(i, 3): mysold = 0
r = Application.Match(B(i, 2), Application.Index(A, 0, 2), 0)
If IsNumeric(r) Then
For i1 = r To UBound(A)
If A(i1, 2) = B(i, 2) And A(i1, 1) <= B(i, 1) Then
x = Application.Max(0, Application.Min(A(i1, 3), iSell))
If x > 0 Then
mysold = mysold + x
iSell = iSell - x
MyValueSold = MyValueSold + x * A(i1, 4)
A(i1, 3) = A(i1, 3) - x
If A(i1, 3) <= 0 Then A(i1, 2) = "~"
End If
If A(i1, 3) > 0 Then Exit For
End If
Next
End If
arr(i, 1) = mysold: arr(i, 2) = MyValueSold
Next
This operation is really slow when using larger arrays:
r = Application.Match(B(i, 2), Application.Index(A, 0, 2), 0)
You can get much better performance just by replacing the Index/Match line with a dictionary lookup.
To illustrate:
Sub Tester()
Const NROWS As Long = 100000
Dim i As Long, r, t
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")
Dim A(1 To NROWS, 1 To 10)
'populate some dummy data
For i = 1 To UBound(A, 1)
A(i, 2) = Application.RandBetween(1, NROWS)
A(i, 3) = i
Next i
'First your existing row lookup...
t = Timer
For i = 1 To 100 'only testing 100 lookups (too slow for more!)
r = Application.Match(i, Application.Index(A, 0, 2), 0)
Next i
Debug.Print "Index/Match lookup", Timer - t, "*100* lookups"
'populate a dictionary for lookups...
t = Timer
For i = 1 To NROWS
dict(A(i, 2)) = i 'mapping second column first occurences to row #
Next i
Debug.Print "Mapping done", Timer - t
'Now the dictionary lookup
t = Timer
For i = 1 To NROWS
If dict.Exists(i) Then
r = dict(i)
End If
Next i
Debug.Print "Dictionary lookup", Timer - t, NROWS & " lookups"
End Sub
Output:
Index/Match lookup 9.62 *100* lookups '<<< slow slow!
Mapping done 0.12
Dictionary lookup 0.26 100000 lookups
EDIT: changes in your existing code
Dim rngMatch As Range '<<< added
'...
'...
Set lo = Sheets("Exc").ListObjects("TBL_Buy")
Set rngMatch = lo.DataBodyRange.Columns(2) '<<< lookup range
With lo.Range
.Sort .Range("B1"), xlAscending, , .Range("A1"), xlAscending, Header:=xlYes
aBuy = lo.DataBodyRange.Value2
.Sort .Range("A1"), xlAscending, , .Range("B1"), xlAscending, Header:=xlYes
End With
'...
For i = 1 To UBound(aResult)
'...
r = Application.Match(aResult(i, 2), rngMatch, 0) '<<<
'...
'...

Array in VBA: For a specific row, gives me the values (corrresponding to the column) and skips the blank cells

I'm currently stuck on a couple of issues in VBA.
I have a data set with multiple rows and columns.
Example would be:
A B C D E F ...
1 Name Food 1 Food 2 Food 3 Food4 Food 5 ...
2 Ami Oranges Twix Pizza Grapes
3 Ben Banana Apples Eggs Coke
4 Mike Peaches Burger Coffee
5 Lea Peas Berries Cake Chips Sprite
...
What I want to do is to have that data read through an array so it gives me the following back:
Name Food 1 Food 2 Food 4 Food 5 ...
Ami Oranges Twix Pizza Grapes
The food of the corresponding name but without including the blank cells or column.
I did find a Youtube video that helped, only issue with the code in the video is that it creates for each row a new worksheet!!
Which I do not want as, there is already a designated worksheet, within the workbook, it's supposed to appear in. Which will later be used as table in an outlook item.
The code I got from Youtube is the following:
Dim CompInfo(0 To 170, 1 To 21)
Dim r As Long, c As Long
Const StartRow As Long = 1
Dim ShNew As Worksheet
For r = 0 To 170
For c = 1 To 21
CompInfo(r, c) = Cells(r + StartRow, c).Value
Next c
Next r
For r = 0 To 170
Set ShNew = Worksheets.Add
ShNew.Name = CompInfo(r, 2)
'Setting the headers
ShNew.Range("A1").Value = CompInfo(0, 1)
ShNew.Range("B1").Value = CompInfo(0, 2)
ShNew.Range("C1").Value = CompInfo(0, 3)
ShNew.Range("D1").Value = CompInfo(0, 4)
ShNew.Range("E1").Value = CompInfo(0, 5)
ShNew.Range("F1").Value = CompInfo(0, 6)
ShNew.Range("G1").Value = CompInfo(0, 7)
ShNew.Range("H1").Value = CompInfo(0, 8)
ShNew.Range("I1").Value = CompInfo(0, 9)
ShNew.Range("J1").Value = CompInfo(0, 10)
ShNew.Range("K1").Value = CompInfo(0, 11)
ShNew.Range("L1").Value = CompInfo(0, 12)
ShNew.Range("M1").Value = CompInfo(0, 13)
ShNew.Range("N1").Value = CompInfo(0, 14)
ShNew.Range("O1").Value = CompInfo(0, 15)
ShNew.Range("P1").Value = CompInfo(0, 16)
ShNew.Range("Q1").Value = CompInfo(0, 17)
ShNew.Range("R1").Value = CompInfo(0, 18)
ShNew.Range("S1").Value = CompInfo(0, 19)
ShNew.Range("T1").Value = CompInfo(0, 20)
ShNew.Range("U1").Value = CompInfo(0, 21)
'Setting the accounts
ShNew.Range("A2").Value = CompInfo(r, 1)
ShNew.Range("B2").Value = CompInfo(r, 2)
ShNew.Range("C2").Value = CompInfo(r, 3)
ShNew.Range("D2").Value = CompInfo(r, 4)
ShNew.Range("E2").Value = CompInfo(r, 5)
ShNew.Range("F2").Value = CompInfo(r, 6)
ShNew.Range("G2").Value = CompInfo(r, 7)
ShNew.Range("H2").Value = CompInfo(r, 8)
ShNew.Range("I2").Value = CompInfo(r, 9)
ShNew.Range("J2").Value = CompInfo(r, 10)
ShNew.Range("K2").Value = CompInfo(r, 11)
ShNew.Range("L2").Value = CompInfo(r, 12)
ShNew.Range("M2").Value = CompInfo(r, 13)
ShNew.Range("N2").Value = CompInfo(r, 14)
ShNew.Range("O2").Value = CompInfo(r, 15)
ShNew.Range("P2").Value = CompInfo(r, 16)
ShNew.Range("Q2").Value = CompInfo(r, 17)
ShNew.Range("R2").Value = CompInfo(r, 18)
ShNew.Range("S2").Value = CompInfo(r, 19)
ShNew.Range("T2").Value = CompInfo(r, 20)
ShNew.Range("U2").Value = CompInfo(r, 21)
Next r
End Sub
Now this code gives partially what I want but it would be could if I could have it without having a new worksheet created for every row.
Not to mention that I also tried adding that it should not show/print those cells that are empty even if the cell above is filled.
If Range("C1").Select <> "" And Range("C2").Select = "" Then
Range("C1:C2").Offset(0, 1).Select
End If
So with every thing what am I doing wrong?
Would be great if someone could help me :)
Thanks you very much
Export to Another Worksheet
Option Explicit
Sub ExportNamesAndFood()
' s - Source
Const sName As String = "Sheet1"
' d - Destination
Const dName As String = "Sheet2"
Const dFirst As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion
Dim srCount As Long: srCount = srg.Rows.Count
If srCount < 2 Then Exit Sub ' no data or only headers
Dim cCount As Long: cCount = srg.Columns.Count
Dim drCount As Long: drCount = (srCount - 1) * 2
Dim sData As Variant: sData = srg.Value
Dim dData As Variant: ReDim dData(1 To drCount, 1 To cCount)
Dim sr As Long
Dim sc As Long
Dim dr As Long
Dim dc As Long
For sr = 2 To srCount
If Len(CStr(sData(sr, 1))) > 0 Then ' name found
' Name
dr = dr + 2
dData(dr - 1, 1) = sData(1, 1)
dData(dr, 1) = sData(sr, 1)
' Food
dc = 1
For sc = 2 To cCount
If Not IsEmpty(sData(sr, sc)) Then ' food found
dc = dc + 1
dData(dr - 1, dc) = sData(1, sc)
dData(dr, dc) = sData(sr, sc)
'Else ' food not found
End If
Next sc
'Else ' no name found
End If
Next sr
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dCell As Range: Set dCell = dws.Range(dFirst)
Dim drg As Range: Set drg = dCell.Resize(dr, cCount)
drg.Value = dData
MsgBox "Data exported.", vbInformation
End Sub

How to create a 3 dimensional array and then pull info 1 dimension at a time?

I would like to take data sets from Sheet 1 and fill in table values in Sheet 2. I believe using a multidimensional array to be the optimum way of accomplishing this.
Sheet 1 is setup as such:
Column A = "Dates", Column C = "SNs", Column E = "M0s", and Column F = "HNs".
An operator enters in an M0 value, and if a ("E").Row has that value, I want that row's SN, HN, and Date to be entered into Sheet 2. Just because two rows have the same M0 doesn't mean they have the same SN, HN, or Date. I would like each row's values to be stored separately, hence a multidimensional array (3 dimensional in this case).
The code below is my successful attempt at storing all SNs in an single dimensional array (based on M0 entered) and then entering those values into Sheet 2.
Sub FillSheet2()
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long 'could be substituted with Variant or String
ReDim varSNarray(0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray)) = SNcell
ReDim Preserve varSNarray(UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 99 Then
Set ws2range = ws2.Range("AA6:AA55")
ws2SNcellnum = i - 94
ws2.Range("AA" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 49 Then
Set ws2range = ws2.Range("N6:N55")
ws2SNcellnum = i - 44
ws2.Range("N" & ws2SNcellnum).Value = varSNarray(i)
Else
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
End If
Next i
End Sub
I would like to add HN and Date along with SN as this sub runs. I don't know how to augment the array to allow for HN and Date storage though. Below is how I imagine it would look like. However, I cannot successfully create my array. I'm fairly sure it has something to do with my variable setups.
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long
Dim HNcell As Long
Dim Datecell As Long
ReDim varSNarray(0, 0, 0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray), HNcell, Datecell) = SNcell
varSNarray(SNcell, UBound(varSNarray), Datecell) = HNcell 'Script out of range error
varSNarray(SNcell, HNcell, UBound(varSNarray)) = Datecell
ReDim Preserve varSNarray(UBound(varSNarray) + 1, UBound(varSNarray) + 1, UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(Datecell)
''''
Removed this section has its the same as above
''''
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(Datecell)
End If
Next i
How do I store data into a 3 dimensional array and then successful pull 1 dimension from the array at a time?
I don't think an array is necessary here, just write the records to Sheet 2 as they are found. For example
Option Explicit
Sub FillSheet2()
Const COL_DATE = "A"
Const COL_SN = "C"
Const COL_M0 = "E"
Const COL_HN = "F"
Const START_ROW = 7
' target sheet
Const TARGET_START_ROW = 5
Const TARGET_START_COL = 1 'A
Const COL_REPEAT = 13 ' N, AA, AN
Const MAX_ROWS = 50
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Sheets("Sheet1")
Set wsTarget = wb.Sheets("Sheet2")
wsTarget.Cells.Clear
Dim iRow As Integer, iLastRow As Integer, iCount As Integer
Dim iTargetRow As Integer, iTargetCol As Integer, sM0 As String
Dim varPrintM0 As String
iTargetCol = TARGET_START_COL
iTargetRow = TARGET_START_ROW
varPrintM0 = "Test4"
iCount = 0
iLastRow = wsSource.Range(COL_M0 & Rows.Count).End(xlUp).Row
' ----------
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
.Offset(0, 0) = wsSource.Range(COL_SN & iRow).Value
.Offset(0, 1) = wsSource.Range(COL_HN & iRow).Value
.Offset(0, 2) = wsSource.Range(COL_DATE & iRow).Value
End With
iTargetRow = iTargetRow + 1
If iTargetRow >= MAX_ROWS + TARGET_START_ROW Then
iTargetCol = iTargetCol + COL_REPEAT
iTargetRow = TARGET_START_ROW
End If
iCount = iCount + 1
End If
Next
End With
MsgBox iCount & " rows copied", vbInformation, "Finished"
' --------
End Sub
If you do want to use an array replace the code between the ------ lines above with this
Dim ar(5, 50, 3) As Variant ' max of 5 blocks of 50 records
Dim t As Integer, r As Long
t = 1: r = 1
' fill array
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
ar(t, r, 0) = sM0
ar(t, r, 1) = wsSource.Range(COL_SN & iRow).Value
ar(t, r, 2) = wsSource.Range(COL_HN & iRow).Value
ar(t, r, 3) = wsSource.Range(COL_DATE & iRow).Value
End With
r = r + 1
If r > MAX_ROWS Then
r = 1
t = t + 1
End If
iCount = iCount + 1
End If
Next
End With
' output array
Dim iLastTable As Long, c As Long
iLastTable = t
For t = 1 To iLastTable
For r = 1 To 50
c = 1 + COL_REPEAT * (t - 1)
With wsTarget.Cells(r + 4, c)
.Offset(0, 0) = ar(t, r, 1)
.Offset(0, 1) = ar(t, r, 2)
.Offset(0, 2) = ar(t, r, 3)
End With
Next r
Next t
MsgBox iCount & " rows copied using Array", vbInformation, "Finished"

Manipulating workbook data with two arrays

I am trying to get the information from one workbook, transform it to array (2D), add the first column (identifier) to an identifier array, match and paste it to excel. The code has some extra lines for basic organization.
The current problem is that, in the IsInArray function, I am getting a "subscript not defined", for the 'for position = LBound(arr) to UBound(arr)'.
Any idea of what might be happening?
Sub Pr()
Dim w As Workbook
Set w = ThisWorkbook
Dim w2 As Workbook
Dim end1 As Long, end2 As Long, i As Long, lRow As Long, lColumn As Long, t As Long, k As Long, position As Long, g As Long
Dim WBArray() As Variant
Dim IS() As Variant
Dim ws As Worksheet
end1 = ThisWorkbook.Worksheets(1).UsedRange.Rows.count
Dim MyFolder As String
Dim MyFile As String
'Optimize Macro Speed Start
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
'opens the first workbook file
For i = 2 To ThisWorkbook.Sheets("FILES").Cells(1, 2).Value
Workbooks.Open Filename:=ThisWorkbook.path & "\" & ThisWorkbook.Sheets("FILES").Cells(i, 1).Value
Set w2 = ActiveWorkbook
ActiveSheet.Range("A:A").Select
'text to columns
Selection.TextToColumns destination:=Range("A1"), DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=True, Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), Array(7 _
, 1), Array(8, 1), Array(9, 1), Array(10, 1), Array(11, 1), Array(12, 1), Array(13, 1), Array(14, 1), Array(15, 1), Array(16, 1), Array(17 _
, 1), Array(18, 1), Array(19, 1), Array(20, 1), Array(21, 1), Array(22, 1), Array(23, 1), Array(24, 1), Array(25, 1), Array(26, 1), Array(27 _
, 1), Array(28, 1), Array(29, 1), Array(30, 1), Array(31, 1), Array(32, 1)), TrailingMinusNumbers:=True
end2 = ActiveSheet.UsedRange.Rows.count
'transform it to array
WBArray = ActiveSheet.Range(Cells(5, 1), Cells(end2, 29)).Value
'loop to match information in two arrays
For lRow = 2 To UBound(WBArray)
If IsInArray((WBArray(lRow, 1)), IS) <> -1 Then
t = IsInArray((WBArray(lRow, 1)), IS)
'start the information pasting procedure:
w.Sheets("C").Cell(t, i + 3) = WBArray(lRow, 11)
w.Sheets("M").Cell(t, i + 3) = WBArray(lRow, 12)
w.Sheets("W t-1").Cell(t, i + 3) = WBArray(lRow, 13)
w.Sheets("P").Cell(t, i + 3) = WBArray(lRow, 14)
w.Sheets("A").Cell(t, i + 3) = WBArray(lRow, 15)
w.Sheets("PC").Cell(t, i + 3) = WBArray(lRow, 16)
w.Sheets("AM").Cell(t, i + 3) = WBArray(lRow, 17)
w.Sheets("AM t-1").Cell(t, i + 3) = WBArray(lRow, 18)
w.Sheets("P t-1").Cell(t, i + 3) = WBArray(lRow, 19)
w.Sheets("F").Cell(t, i + 3) = WBArray(lRow, 20)
w.Sheets("F t-1").Cell(t, i + 3) = WBArray(lRow, 21)
w.Sheets("A t-1").Cell(t, i + 3) = WBArray(lRow, 22)
w.Sheets("S").Cell(t, i + 3) = WBArray(lRow, 23)
Else
'add it to the end of ISArray
ReDim Preserve IS(1 To UBound(IS) + 1)
IS(UBound(IS)) = WBArray(lRow, 1)
k = UBound(IS)
w.Sheets("C").Cell(k, i + 3) = WBArray(lRow, 11)
w.Sheets("M").Cell(k, i + 3) = WBArray(lRow, 12)
w.Sheets("W t-1").Cell(k, i + 3) = WBArray(lRow, 13)
w.Sheets("P").Cell(k, i + 3) = WBArray(lRow, 14)
w.Sheets("A").Cell(k, i + 3) = WBArray(lRow, 15)
w.Sheets("PC").Cell(k, i + 3) = WBArray(lRow, 16)
w.Sheets("AM").Cell(k, i + 3) = WBArray(lRow, 17)
w.Sheets("AM t-1").Cell(k, i + 3) = WBArray(lRow, 18)
w.Sheets("P t-1").Cell(k, i + 3) = WBArray(lRow, 19)
w.Sheets("F").Cell(k, i + 3) = WBArray(lRow, 20)
w.Sheets("F t-1").Cell(k, i + 3) = WBArray(lRow, 21)
w.Sheets("A t-1").Cell(k, i + 3) = WBArray(lRow, 22)
w.Sheets("S").Cell(k, i + 3) = WBArray(lRow, 23)
End If
Next lRow
'copy the file date from each source workbook to output workbook
'if the control sheet name (FILES) is changed, please change it in this loop
For Each ws In w.Worksheets
If ws.Name <> "FILES" Then
ws.Cells(1, i + 3) = w2.Worksheets(1).Cells(1, 2)
End If
Next ws
Next i
'paste the is array to all worksheets
g = UBound(IS)
For Each ws In ActiveWorkbook.Worksheets
Range("A1:A" & g) = IS()
Next ws
'Optimize Macro Speed
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
'Close file and save
'w.Close True
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim position As Long
'default return value if value not found in array
IsInArray = -1
For position = LBound(arr) To UBound(arr) 'subscript out of range
If arr(position) = stringToBeFound Then
IsInArray = position + 1
Exit For
End If
Next
End Function
Your problem is that when you test the LBOUND of an unallocated array, you will get an error. And that will be the case on the first pass through your IsInArray function.
Since links to outside websites are discouraged, I have copied the IsArrayEmpty function from Chip Pearson's web site page on VBA Arrays
Change your IsInArray function as follows (and add the IsArrayEmpty function as I show below:
Function IsInArray(stringToBeFound As String, Arr As Variant) As Long
Dim position As Long
'default return value if value not found in array
IsInArray = -1
If IsArrayEmpty(Arr) Then Exit Function
For position = LBound(Arr) To UBound(Arr) 'subscript out of range
If Arr(position) = stringToBeFound Then
IsInArray = position + 1
Exit For
End If
Next
End Function
Public Function IsArrayEmpty(Arr As Variant) As Boolean
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'From Chip Pearson [VBA Arrays](http://www.cpearson.com/excel/vbaarrays.htm)
' IsArrayEmpty
' This function tests whether the array is empty (unallocated). Returns TRUE or FALSE.
'
' The VBA IsArray function indicates whether a variable is an array, but it does not
' distinguish between allocated and unallocated arrays. It will return TRUE for both
' allocated and unallocated arrays. This function tests whether the array has actually
' been allocated.
'
' This function is really the reverse of IsArrayAllocated.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim LB As Long
Dim UB As Long
Err.Clear
On Error Resume Next
If IsArray(Arr) = False Then
' we weren't passed an array, return True
IsArrayEmpty = True
End If
' Attempt to get the UBound of the array. If the array is
' unallocated, an error will occur.
UB = UBound(Arr, 1)
If (Err.Number <> 0) Then
IsArrayEmpty = True
Else
''''''''''''''''''''''''''''''''''''''''''
' On rare occassion, under circumstances I
' cannot reliably replictate, Err.Number
' will be 0 for an unallocated, empty array.
' On these occassions, LBound is 0 and
' UBoung is -1.
' To accomodate the weird behavior, test to
' see if LB > UB. If so, the array is not
' allocated.
''''''''''''''''''''''''''''''''''''''''''
Err.Clear
LB = LBound(Arr)
If LB > UB Then
IsArrayEmpty = True
Else
IsArrayEmpty = False
End If
End If
End Function
In your function IsInArray, can you try this :
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim position As Long
Dim returnValue as Long
'default return value if value not found in array
returnValue = -1
For position = LBound(arr) To UBound(arr) 'subscript out of range
If arr(position) = stringToBeFound Then
returnValue = position + 1
Exit For
End If
Next
IsInArray = returnValue
End Function`
I think when you write : IsInArray = -1, you're ending your function.

Consolidating values on an unevenly spaced spreadsheet Excel VBA

Writing rudimentary VBA to populate a 2 dimensional array filled with two sums one consisting of the odd columns the other is the sum of the even columns, totaled over a variable amount of rows stored in another array. the two dimensional array then prints on a seperate worksheet. I wrote code which succesfully completed this task on two other worksheets in the same file with slightly different sized arrays, but it populates the destination range with zeros when adjusted for the new input and output.
code in question:
Sub dad()
Dim i As Integer, j As Integer, units As Double, value As Double, mr(1 To 655, 1 To 3) As Double, u As Integer, here As Range
Dim thisone As String, there As Range
thisone = Worksheets("MB52 for 1010").Cells(1, 1).Address
Set here = Range(thisone)
MsgBox (here(1, 1).Address)
thisone = Worksheets("1010totals").Cells(1, 1).Address
Set there = Range(thisone)
MsgBox (there(1, 1).Address)
For i = 1 To 655
mr(i, 1) = Worksheets("1010totals").Cells(i + 1, 4).value
Next i
MsgBox ("array made")
i = 1
u = 1
MsgBox (i & " " & u)
For i = 1 To 655
For j = 1 To mr(i, 1)
u = u + 1
units = here(u, 6) + here(u, 9) + here(u, 11).value + here(u, 13) + here(u, 15) + here(u, 17)
value = here(u, 8) + here(u, 10) + here(u, 12).value + here(u, 14) + here(u, 16) + here(u, 18)
Next j
mr(i, 2) = units
mr(i, 3) = value
Next i
For i = 1 To 655
For j = 2 To 3
Worksheets("1010totals").Cells(i + 1, j).value = mr(i, j)
Next j
Next i
End Sub
Original code that works on the other worksheets:
Sub ded()
Dim i As Integer, j As Integer, units As Double, value As Double, n As Integer, mr(1 To 756, 1 To 3) As Double, u As Integer, here As Range
Dim thisone As String, there As Range
thisone = Worksheets("MB52 for 1030").Cells(1, 1).Address
Set here = Range(thisone)
MsgBox (here(1, 1).Address)
thisone = Worksheets("1030totals").Cells(1, 1).Address
Set there = Range(thisone)
MsgBox (there(1, 1).Address)
For i = 1 To 756
mr(i, 1) = Worksheets("1030totals").Cells(i + 1, 4).value
Next i
MsgBox ("array made")
i = 1
u = 1
MsgBox (i & " " & u)
For i = 1 To 756
For j = 1 To mr(i, 1)
u = u + 1
units = here(u, 6) + here(u, 9) + here(u, 11).value + here(u, 13) + here(u, 15) + here(u, 17)
value = here(u, 8) + here(u, 10) + here(u, 12).value + here(u, 14) + here(u, 16) + here(u, 18)
Next j
mr(i, 2) = units
mr(i, 3) = value
Next i
For i = 1 To 756
For j = 2 To 3
Worksheets("1030totals").Cells(i + 1, j).value = mr(i, j)
Next j
Next i
End Sub

Resources