Passing an array to subroutine VBA - arrays

I'm working on a macro for excel and have a sub that passes an array to another sub, but I keep getting
Run time error '9'
Subscript out of range
below is my code and I left a comment pointing to where this error is occurring. I'm new to VBA so it's possible I'm trying to pass an array incorrectly not sure though.
'Main Driver
Sub Main()
WorkbookSize = size() 'Run function to get workbook size
newbook = False
Call create 'Run sub to create new workbook
Call pull(WorkbookSize) 'Run sub to pull data
End Sub
'Get size of Worksheet
Function size() As Integer
size = Cells(Rows.Count, "A").End(xlUp).Row
End Function
'Create workbook
Sub create()
Dim wb As Workbook
Set wb = Workbooks.Add
TempPath = Environ("temp")
With wb
.SaveAs Filename:=TempPath & "EDX.xlsm" _
, FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
.ChangeFileAccess Mode:=xlReadOnly, WritePassword:="admin"
End With
End Sub
'pull data
Sub pull(size)
Dim code() As Variant
For i = 1 To size
'Check code column fo IN and Doctype column for 810
If Cells(i, 18).Value = "IN" Then
code(i) = Cells(i, 18).Value 'store in array
End If
Next i
Call push(code)
End Sub
'push data to new workbook
Sub push(ByRef code() As Variant)
activeBook = "TempEDX.xlsm"
Workbooks(activeBook).Activate 'set new workbook as active book
For i = 1 To UBound(code) ' <---here is where the error is referencing
Cells(i, 1).Value = code(i)
Next i
End Sub
Any help is appreciated.

You're problem is that you don't correctly initialize the code array.
Do so using Redim See the modification below:
'pull data
Sub pull(size)
Dim code() As Variant
Redim code(size-1) '<----add this here minus 1 because 0 index array
For i = 1 To size
'Check code column fo IN and Doctype column for 810
If Cells(i, 18).Value = "IN" Then
code(i-1) = Cells(i, 18).Value 'store in array subtract 1 for 0 index array
End If
Next i
Call push(code)
End Sub
Also, you'll need to update your Push method's code to accommodate the 0-indexed array
'push data to new workbook
Sub push(ByRef code() As Variant)
activeBook = "TempEDX.xlsm"
Workbooks(activeBook).Activate 'set new workbook as active book
For i = 0 To UBound(code) ' <0 to ubound
Cells(i+1, 1).Value = code(i) 'add 1 to i for the cells reference
Next i
End Sub

I will add these other points
You are also working with Rows but have Integer as a return for a function risking overflow
e.g.
Function size() As Integer
Change to a Long.
You have lots of implicit activesheet references. Get rid of those and give a parent sheet. For example, you could set the sheet in a variable called ws and pass, if required, as a parameter.
E.g.
Public Function size(ByVal ws As Worksheet) As Long
With ws
size = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
End Function
As mentioned, put Option Explicit at the top of your code and declare all your variables.

Related

Extract subarray from jagged array and use as 1d array

I'm trying to reduce redundancy in my macros but I'm struggling with getting an element from a jagged array and using it elsewhere.
The premise is a single workbook with many sheets being split by groups of sheet names into new documents that I can then send to the process owners so they only get their own data.
Previously I was selecting sheet names listed explicitly and pasting to a new document that was named explicitly, but I had to run 10 separate almost identical macros to do that and I have heard of select being a bad choice in many instances as well.
Below is my latest attempt, the first issue is at the printOut line I get a Type Mismatch.
Sub CopyOut()
Dim printOut, groupNames, Group1, groupArray() As Variant
Dim n, j As Long
Dim reNamed, fileName As String
Dim ws As Worksheet
Dim wb1, wb2 As Workbook
groupNames = Array("Group 1", "Group 2", "Group 3", "Group 4") 'other arrays left off for length
Group1 = Array("FA_1A Report", "FA_1A", "FA_2ACS Report", "FA_2ACS", "FA_2BCS Report", "FA_2BCS", "FANUCMED Report", "FANUCMED", "FA_RRTP1 Report", "FA_RRPT1")
groupArray = Array(groupNames, Group1)
For n = 1 To UBound(groupArray)
fileName = "CS Data Sheet" & " " & Format(Date, "mmmyy") & "-" & groupArray(n - n)(n - 1) & ".xlsm" 'concat file name string. this is not just tacked on the end of reName because i use it on it's own later
reNamed = "C:\Users\xx\Desktop\" & fileName 'concat save location string
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Add 'create a new workbook, wb2
wb2.SaveAs fileName:=reNamed, FileFormat:=xlOpenXMLWorkbookMacroEnabled 'save with that name and location
printOut = Join(Application.Index(groupArray, n, 0), ",")
wb1.Sheets(printOut).Copy Before:=Workbooks(fileName).Sheets(1) 'copy the sheets for the group and paste into the newly created document
Next
End Sub
If I nix printOut altogether and put in a specific worksheet name instead it does work for just that one sheet (of course) but I need it to copy multiple to each new document.
I have also tried:
For n = 1 To UBound(groupArray)
...
for j= LBound(groupArray(n)) To UBound(groupArray(n))
wb1.Sheets(groupArray(n)(j)).Copy Before:=Workbooks(fileName).Sheets(1)
next
next
to iterate through the subarray and copy a sheet at a time, but it gives subscript out of range. With this version I tried various methods of making the groupArray(n)(j) value into a string or into a "worksheet" type to set as a variable and use the variable in the sheets().copy, to no avail.
Any idea where I could be going wrong?
thanks so much
EDIT:
I got my above code working by wrapping it in split (was trying to use printOut as an array when it was only a string) and fixing the arguments of Index as below, however the resulting code still needs work, since if a sheet is missing it won't run.
printOut = Split(Join(Application.Index(groupArray(n), 1, 0), ","), ",")
In my experience, if you find yourself hard-coding values like sheet names, group names, and other data directly in your code it tends to become difficult to maintain. Adding more groups, or re-shuffling the sheets in each group becomes problematic. My recommendation is to create a (possibly hidden) worksheet that maps your worksheet names into groups. Then you have a small set of code that operates directly on that.
My example data is set up like this:
Next, in its own code module, I created a few methods to work directly with this group map data. The main idea here is to move the group map data into a memory-based array. While in general I rarely use module-level global variables, I have one in this example to illustrate how to work with the data by only reading it into the array once every time the macro is executed.
(These are Subs and Functions. For my own code, I likely would have created a VBA class to handle the data in an object-oriented way.)
So there is a Private Sub to get the data:
Option Explicit
Private groupData As Variant
Private Sub GetGroupData()
Const GROUP_WS_NAME As String = "GroupMap"
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(GROUP_WS_NAME)
Dim lastRow As Long
Dim lastCol As Long
With ws
'--- how many columns of groups?
lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
lastRow = .UsedRange.Find("*", , , , xlByRows, xlPrevious).Row
groupData = .Range("A1").Resize(lastRow, lastCol).Value
End With
End Sub
Now it's easy to figure out how many groups there are:
Public Function NumberOfGroups() As Long
If IsEmpty(groupData) Then GetGroupData
NumberOfGroups = UBound(groupData, 2)
End Function
And how many items in a particular group:
Public Function NumberInGroup(ByVal groupNumber As Long)
If IsEmpty(groupData) Then GetGroupData
'--- count the number of array values that have data
Dim i As Long
For i = LBound(groupData, 1) To UBound(groupData, 1)
If groupData(i, groupNumber) = vbNullString Then
'--- we found the first empty cell in this array, we're done
Exit For
Else
NumberInGroup = NumberInGroup + 1
End If
Next i
'--- subtract one to discount the header value
NumberInGroup = NumberInGroup - 1
End Function
The easiest of all is getting the value of any group:
Public Function GetGroupValue(ByVal groupNumber As Long, _
ByVal groupIndex As Long) As Variant
If IsEmpty(groupData) Then GetGroupData
'--- always add one to the index to account for the header value
GetGroupValue = groupData(groupIndex + 1, groupNumber)
End Function
Notice the check for If IsEmpty(groupData) Then GetGroupData at the beginning of each method. This makes sure the groupData array is always loaded if necessary.
This example gives it a quick test (in a different code module):
Option Explicit
Sub test()
Dim totalGroups As Long
totalGroups = NumberOfGroups()
Dim i As Long
Dim j As Long
For i = 1 To totalGroups
Dim totalInGroup As Long
totalInGroup = NumberInGroup(i)
For j = 1 To totalInGroup
Debug.Print "group " & i & " = " & GetGroupValue(i, j)
Next j
Next i
End Sub
Here's the whole group data code module in a single block:
Option Explicit
Private groupData As Variant
Private Sub GetGroupData()
Const GROUP_WS_NAME As String = "GroupMap"
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(GROUP_WS_NAME)
Dim lastRow As Long
Dim lastCol As Long
With ws
'--- how many columns of groups?
lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
lastRow = .UsedRange.Find("*", , , , xlByRows, xlPrevious).Row
groupData = .Range("A1").Resize(lastRow, lastCol).Value
End With
End Sub
Public Function NumberOfGroups() As Long
If IsEmpty(groupData) Then GetGroupData
NumberOfGroups = UBound(groupData, 2)
End Function
Public Function NumberInGroup(ByVal groupNumber As Long)
If IsEmpty(groupData) Then GetGroupData
'--- count the number of array values that have data
Dim i As Long
For i = LBound(groupData, 1) To UBound(groupData, 1)
If groupData(i, groupNumber) = vbNullString Then
'--- we found the first empty cell in this array, we're done
Exit For
Else
NumberInGroup = NumberInGroup + 1
End If
Next i
'--- subtract one to discount the header value
NumberInGroup = NumberInGroup - 1
End Function
Public Function GetGroupValue(ByVal groupNumber As Long, ByVal groupIndex As Long) As Variant
If IsEmpty(groupData) Then GetGroupData
'--- always add one to the index to account for the header value
GetGroupValue = groupData(groupIndex + 1, groupNumber)
End Function
If I got this right, you have one master workbook with n sheets and you want to group some of them, then create a new workbook for each group and paste in its assigned sheets.
I think an approach where you keep a "config" file in your master workbook for setting up groups and sheets, is more suitable rather than editing into code. Example:
The below code will create a file using the names from column A and copy all the sheets defined on their respective row.
Option Explicit
Sub CopyOut()
Dim groupArr() As Variant
Dim wb2 As Workbook
Dim lastRow As Long, lastCol As Long, highestNumOfSheets As Long, i As Long, j As Long, arrColumns As Long
Dim reNamed As String, fileName As String, configSheet As String
Dim removedSheet1 As Boolean
' Modify the sheet name here
configSheet = "config"
' Build an array from sheet defined groups
With ThisWorkbook.Worksheets(configSheet)
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To lastRow
lastCol = .Cells(i, .Columns.Count).End(xlToLeft).Column
If lastCol > highestNumOfSheets Then highestNumOfSheets = lastCol
Next i
groupArr = .Range(.Cells(2, 1), .Cells(lastRow, highestNumOfSheets)).Value2
End With
Application.ScreenUpdating = False
For i = LBound(groupArr) To UBound(groupArr)
fileName = "CS Data Sheet " & Format(Date, "mmmyy") & "-" & groupArr(i, 1) & ".xlsm"
reNamed = Environ("UserProfile") & "\Desktop\" & fileName
removedSheet1 = False ' Reset this on each new workbook created
Set wb2 = Workbooks.Add
' Pick all the sheet names for the current group
For j = 2 To UBound(groupArr, 2)
' Skip empty values from array (if it's the case) and skip missing sheets
If Trim(groupArr(i, j)) <> vbNullString And SheetExists(groupArr(i, j)) Then
ThisWorkbook.Worksheets(groupArr(i, j)).Copy Before:=wb2.Worksheets(1)
' Remove Sheet1 from the new Workbook
If removedSheet1 = False Then
With Application
.DisplayAlerts = False
wb2.Worksheets("Sheet1").Delete
removedSheet1 = True
.DisplayAlerts = True
End With
End If
End If
Next j
' Here you might need an error handler if you think you're going to run the macro multiple times in the same day
' If the file exists already this will throw an error
' A quick lazy way is to add time (including seconds) when you define the file name above
wb2.SaveAs fileName:=reNamed, FileFormat:=xlOpenXMLWorkbookMacroEnabled
wb2.Close
If Not wb2 Is Nothing Then Set wb2 = Nothing
Next i
Application.ScreenUpdating = True
End Sub
Function SheetExists(ByVal sheetName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Worksheets(sheetName)
On Error GoTo 0
If Not ws Is Nothing Then
SheetExists = True
Set ws = Nothing
End If
End Function
Of course it can be tweaked around, with error handling and other checks (depending on what you want to achieve entirely) but it should give you an alternative view of your code.
EDIT: Added a function to check if sheet exists.

Delete all contents except for first row for specific sheets in Excel

Please assist. I have this code here and it works for first sheet however, does not execute in the 2nd sheet. I think i'm missing a sheet syntax. thanks.
Dim arrSheets As Variant, sht As Variant
arrSheets = Array("tl_1", "tl_2")
For Each sht In arrSheets
Sheets(sht).UsedRange.Offset(1).ClearContents
Next sht
My 2 cents: do not rely on worksheet names. Instead, work with their (Name) property as seen from the Visual Basic Editor. Note that you can give significant names yourself instead of the default Sheet1..N ones. This way, your code will survive modifications to the names as seen from Excel, in the tabs at the bottom.
Option Explicit
Public Sub DoTheClearThing()
Dim loopVariant As Variant
Dim loopWorksheet As Excel.Worksheet
Dim worksheetsToConsider As Variant
'Use the (Name) property, as seen from the Visual Basic Editor, of the worksheets you're interested in.
'The array below is not a string array; it is an array of worksheet objects.
worksheetsToConsider = Array(TL_1, TL_2)
'The For's variable must be a Variant; you can then Set it to a variable of the Worksheet type and enjoy Intellisense.
For Each loopVariant In worksheetsToConsider
Set loopWorksheet = loopVariant
loopWorksheet.UsedRange.Offset(1).ClearContents
Next
End Sub
Here's what the worksheets' (Name) properties look like in my test Excel workbook:
From within your workbook's code, you can directly interact with worksheet objects using their (Name) property. Avoid ThisWorkbook.Worksheets("tl_1").SomeMethod and directly go with TL_1.SomeMethod. By the way, a worksheet's (Name) property can be read by code using its CodeName property.
Option Explicit
'This will do something to your target sheets,
'just make sure your "something" is what you want
Dim N As Long
Dim wsName As String
'Optional if included
For N = 1 To ThisWorkbook.Sheets.Count
wsName = ThisWorkbook.Worksheets(N).Name
If wsName = "tl_1" or wsName = "tl_2" Then
ThisWorkbook.Worksheets(N).UsedRange.Offset(1).ClearContents
Else 'Do Nothing
End If
Next N
Note: This is very worksheet name dependent and users can change those if you are not the only user. You may want to CodeName your sheets (properties Explorer and change the Name) then pull the CodeName.
You can use an array to hold the sheets names but it seems like more trouble than its worth unless you are going to load the names into the array.
-WWC
Worksheet.UsedRange does not always return the correct address. Consider the results of the test below:
Test Used Range
Sub Test()
Application.ScreenUpdating = False
Dim cell As Range, target As Range
Debug.Print "Data Range", "|"; "UsedRange"
Debug.Print String(24, "_")
With Worksheets.Add
Set target = .Range("B2:D2")
target.Value = 1
Debug.Print target.Address, "|"; .UsedRange.Address
End With
With Worksheets.Add
.Range("A1:G10").Interior.Color = 65535
Set target = .Range("B2:D2")
target.Value = 1
Debug.Print target.Address, "|"; .UsedRange.Address
End With
End Sub
Clear Non-Headers
Sub ClearNonHeaderRows()
Dim arrSheets As Variant, sht As Variant
Dim cell As Range
arrSheets = Array("tl_1", "tl_2")
For Each sht In arrSheets
With Worksheets(sht).UsedRange
Set cell = .Find("*", .Cells(1, 1))
If Not cell Is Nothing Then
cell.Offset(1).Resize(.Cells.Rows.Count - cell.row + .Cells(1, 1).row).EntireRow.ClearContents
End If
End With
Next sht
End Sub

Redim Preserve a 2D Array from Excel Table

Try as I might I cannot correct a "Subscript out of Range" error that the code below is throwing on the last line of code below when I try to expand the size of an array with Redim Preserve. Any ideas as to what might be wrong?
Sub Demo()
'Set Excel variables
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim wsCluster As Worksheet: Set wsCluster = wb.Worksheets("Cluster")
Dim initialK As ListObject: Set initialK = wsCluster.ListObjects("k")
'Set Array variables
Dim kArray() As Variant
ReDim kArray(1 To initialK.DataBodyRange.Rows.Count, 1 To initialK.DataBodyRange.Columns.Count)
kArray = initialK.DataBodyRange
'Set Other variables
Dim coordResults As Variant, kResults As Variant, addKs As Variant, dupeArray As Variant
Dim transferLat As Double, transferLong As Double, potDupeCount As Long, expandK As Long, nextAvailK As Long
'Run the assignment function once, then loop through average/assign functions
coordResults = Assign(coordArray, kArray)
For i = 1 To 3
kResults = Average(coordArray, kArray, coordResults)
coordResults = Assign(coordArray, kArray)
Next i
'Run the radius function
addKs = AdjustForRadius(coordArray, kResults, coordResults)
'Add the new, deduped centroid data to the kResults array
expandK = UBound(addKs, 1) + UBound(kArray, 1)
ReDim Preserve kArray(1 To expandK, 1 To 3)
End Sub
The functions are working properly. The "expand" variable is good.
I have tested everything I know.
Jake

How to input a range object to a function and return an array in VBA?

I have a procedure which generates cell range depending on certain criteria.
I also have a function which takes a cell range object as input and returns an array. However, if I call the function within a procedure, I get this error. "Compile error: Can't assign to array" Is there something wrong with my syntax? Thanks.
Option Explicit
'Reads a database table from current Active worksheet and paste to output sheet
Function DBReader(DBMarker As Range) As String
Dim arr(5) As String
'Read data
arr(0) = ActiveWorksheet.DBMarker.Value
arr(1) = ActiveWorksheet.DBMarker.Offset(1, 1).Value
arr(2) = ActiveWorksheet.DBMarker.Offset(2, 1).Value
arr(3) = ActiveWorksheet.DBMarker.Offset(0, 2).Value
arr(4) = ActiveWorksheet.DBMarker.Offset(1, 2).Value
arr(5) = ActiveWorksheet.DBMarker.Offset(2, 2).Value
DBReader = arr()
End Function
The procedure is kinda long, so I'll only show relevant lines
Public Sub LogSum()
'Declare variables
...
Dim DBInfo(5) As String 'Stores info from function
...
Set CellDB = bookLOG.Worksheets(j).UsedRange.Find("Ref:", LookIn:=xlValues)
...
DBInfo = DBReader(CellDB) 'Returns Array from function???
...
End Sub
Give this a try...
Function DBReader(DBMarker As Range) As Variant
Dim arr(5) As String
'Read data
arr(0) = DBMarker.Value
arr(1) = DBMarker.Offset(1, 1).Value
arr(2) = DBMarker.Offset(2, 1).Value
arr(3) = DBMarker.Offset(0, 2).Value
arr(4) = DBMarker.Offset(1, 2).Value
arr(5) = DBMarker.Offset(2, 2).Value
DBReader = arr()
End Function
Public Sub LogSum()
'Declare variables
Dim CellDB As Range
Dim DBInfo() As String 'Stores info from function
Set CellDB = bookLOG.Worksheets(j).UsedRange.Find("Ref:", LookIn:=xlValues)
DBInfo = DBReader(CellDB) 'Returns Array from function???
End Sub
So, there's a couple of issues you need to look at.
First, let's start with your subroutine.
You are declaring an array with 6 elements before you assign it. Let's leave that blank by changing Dim DBInfo(5) to Dim DBInfo()
You should also add a check in your subroutine to make sure you don't have an empty object for CellDB. After that line add something like:
If CellDB Is Nothing Then...
And create a rule for what happens when it's Nothing.
Public Sub LogSum()
'Declare variables
...
Dim DBInfo() As String
...
Set CellDB = bookLOG.Worksheets(j).UsedRange.Find("Ref:", LookIn:=xlValues)
...
DBInfo = DBReader(CellDB)
...
End Sub
Next, we can look at your function itself. At the end of your declaration As String, you are wanting to pass it off as an array so you could designate as an array by using As String().
Also, the syntax of your line DBReader = arr() is done incorrectly. You should just keep it as DBReader = arr.
Function DBReader(DBMarker As Range) As String()
Dim arr(5) As String
'Read data
arr(0) = ActiveWorksheet.DBMarker.Value
arr(1) = ActiveWorksheet.DBMarker.Offset(1, 1).Value
arr(2) = ActiveWorksheet.DBMarker.Offset(2, 1).Value
arr(3) = ActiveWorksheet.DBMarker.Offset(0, 2).Value
arr(4) = ActiveWorksheet.DBMarker.Offset(1, 2).Value
arr(5) = ActiveWorksheet.DBMarker.Offset(2, 2).Value
DBReader = arr
End Function
Also, in general, it's not advised that you use ActiveWorksheet by instead declaring your worksheets. You can pass this off to your function by adding another argument like:
Function DBReader(DBMarker As Range, ws As WorkSheet)...
Will your function still work? Probably.
Do you want to have to debug it later on when you start using it for other worksheets? Doubtful.
Save yourself a headache now so you don't have to have unnecessary debugging later.
Lastly, I am not entirely sure of your intention with DBInfo, but that is a one-dimensional array. This means that if you were to paste this array to your worksheet that it would come out horizontal unless you were to transpose it.
You can make it easier on yourself now by making it a 2-D array.
I suspect the problem is that you are trying to set your function equal to the array you just populated in the final line of your DBReader function.
DBReader = arr() may be failing since DBReader is a function, not an array.

Excel VBA Loop through array of strings which are the object names inside the loop

I want to use an array of strings that will replace the Worksheet object inside my loop, but I cant seem to figure it out.
If I declare SheetX as Variant, then I get the Object Required Error
If I declare SheetX as Object, then I get Compile Error: For Each variable on arrays must be variant
Sub DeleteAllData()
'SheetsArray = ["BalanceSheetTransposed", "IncomeStatementTransposed", "CashflowStatement"]
Dim SheetsArray(0 To 2) As Variant
Dim SheetX As Object
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
For Each SheetX In SheetsArray
lastrow = SheetX.Cells(Rows.Count, 1).End(xlUp).Row
lastcolumn = SheetX.Cells(1, Columns.Count).End(xlToLeft).Column
SheetX.Range("A2", Cells(lastrow, lastcolumn)).ClearContents
Next SheetX
End Sub
Out of my head 'cause I don't have Excel in this machine. Loop through the strings and set worksheet object.
Sub DeleteAllData()
Dim SheetsArray(0 To 2) As String
Dim SheetX As Worksheet
Dim name as String
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
For Each name In SheetsArray
set SheetX = ActiveWorkbook.worksheets(name)
lastrow = SheetX.Cells(Rows.Count, 1).End(xlUp).Row
lastcolumn = SheetX.Cells(1, Columns.Count).End(xlToLeft).Column
SheetX.Range("A2", Cells(lastrow, lastcolumn)).ClearContents
Next
End Sub
Your major problem was that you were trying to treat the strings stored in the array as if they were worksheets, but they are just strings.
The simplest way to get around it is to use Worksheets(SheetsArray) to return the worksheets that have the names you want to use, and then loop through those worksheets:
Sub DeleteAllData()
Dim SheetX As Worksheet
Dim lastRow As Long
Dim lastColumn As Long
Dim SheetsArray(0 To 2) As Variant
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
'An alternative to the previous 4 lines would be
'Dim SheetsArray As Variant
'SheetsArray = Array("BalanceSheetTransposed", _
' "IncomeStatementTransposed", _
' "CashflowStatement")
'Loop through the worksheets referred to in the array
For Each SheetX In Worksheets(SheetsArray)
With SheetX ' avoids some typing
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
'Existing code would have had issue with the unqualified Cells
'reference in the following line. You should always qualify Cells
'to specify which sheet you mean, because it defaults to
'ActiveSheet.Cells
.Range("A2", .Cells(lastRow, lastColumn)).ClearContents
End With
Next SheetX
End Sub
The Array has to be passed to the Sheets object :
Sub DeleteAllData()
Dim ws As Worksheet
For Each ws In Sheets(Array("BalanceSheetTransposed", "IncomeStatementTransposed", _
"CashflowStatement"))
s.UsedRange.Offset(1).ClearContents
Next
End Sub

Resources