Passing array through a function in vba - excel

I'm trying to call a function to process some data in an array, I will be duplicating this for lots of different reasons, so just want to get the basic foundations right and I'm getting errors with data types. I've simplified my code to try and get it going from the ground up but still can't find the cause.
Sub VBA_Split_Print()
Dim last_row As Long
last_row = Cells(Rows.Count, 1).End(xlUp).Row
Range("J2:AE90000").ClearContents
For J = 2 To last_row
Dim arr() As String
arr = Split(Worksheets("Raw").Cells(J, 9).Value, ",")
Call ElectiveAdd(arr)
Next J
End Sub
Function ElectiveAdd(ByRef arr() As String)
Dim arrLength As Integer
arrLength = UBound(arr, 1) - LBound(arr, 1)
Dim x As Integer
x = 0
For i = 24 To (arrLength + 24)
Worksheets("Raw").Cells(J, i).Value = arr(x)
x = x + 1
Next i
End Function
When I'm trying to run this I am getting an Run-Time Error '1004' Application-Defined or Object-Defined Error message.
So revised code due to feedback and I feel that J is another issue so I have excluded it, thanks for pointing out the error though!
Sub VBA_Split_Print()
Dim last_row As Long
last_row = Cells(Rows.Count, 1).End(xlUp).row
Range("J2:AE90000").ClearContents
Dim arr() As String
arr = Split(Worksheets("Raw").Cells(2, 9).Value, ",")
Call ElectiveAdd(arr)
End Sub
Function ElectiveAdd(ByRef arr() As String)
Dim arrLength As Integer
arrLength = UBound(arr, 1) - LBound(arr, 1)
Dim x As Integer
x = 0
For i = 24 To (arrLength + 24) + 1
Worksheets("Raw").Cells(2, i).Value = arr(x)
x = x + 1
Next i
End Function
Now I am getting a different error message of subscript out of range, cell 2,9 = "

Instead of passing the array, why not pass the cell?
Option Explicit
Sub VBA_Split_Print()
Dim last_row As Long
Dim I As Long
Dim arr() As String
With Worksheets("Raw")
last_row = .Cells(Rows.Count, 1).End(xlUp).Row
.Range("J2:AE90000").ClearContents
For I = 2 To last_row
Call ElectiveAdd(Worksheets("Raw").Cells(I, 9))
Next I
End With
End Sub
Function ElectiveAdd(ByRef rng As Range)
Dim arr As Variant
Dim I As Long
arr = Split(rng.Value, ",")
For I = LBound(arr, 1) To UBound(arr, 1)
rng.Parent.Cells(rng.Row, 24 + I).Value = arr(I)
Next I
End Function
If you still want to pass the array you'll probably need to pass the row as well so the data goes in the right place.
Option Explicit
Sub VBA_Split_Print()
Dim last_row As Long
Dim I As Long
Dim arr() As String
With Worksheets("Raw")
last_row = .Cells(Rows.Count, 1).End(xlUp).Row
.Range("J2:AE90000").ClearContents
For I = 2 To last_row
arr = Split(Worksheets("Raw").Cells(I, 9), ",")
Call ElectiveAdd(arr, I)
Next I
End With
End Sub
Function ElectiveAdd(ByRef arr As Variant, rw As Long)
Dim I As Long
For I = LBound(arr, 1) To UBound(arr, 1)
Worksheets("Raw").Cells(rw, 24 + I).Value = arr(I)
Next I
End Function

Related

Matching 2 Separate Strings with 2 Separate Ranges to Copy the Corresponding Value

I have been trying to match Date with week number i.e. ("B1:F1")
then date with Year-month i.e. ("A2:A500")
If matches then copy the value from this table that i have highlighted according to the date which is available in code where week is 2 and month is May-2021. Can someone please help me to achieve this.
There are multiple dates which i need to iterate with this table to get different values according to weeks and Year-Months.
Your help will be much appreciated.
Sub findMatchingRecords()
Dim rng1 As Range
Dim rng2 As Range
Dim ws As Worksheet
Dim getdate As String
Dim GetWeek As String
Set ws = Worksheets("Sheet1")
getdate = ws.Range("N1").Value
GetWeek = Int((Day(getdate) + 6) / 7)
Set rng1 = ws.Range("B1:F1")
Set rng2 = ws.Range("A2:A500")
For Each rng1cell In rng1
For Each rng2cell In rng2
If rng1cell = GetWeek And rng2cell = Format(getdate, "yyyy-mmm") Then
'Copy value and paste into Sheet1.Range("M2")
End If
Next rng1cell
Next rng2cell
End Sub
Here are the dates which needs to match with table and get relevant the value.
5/13/2021
5/16/2021
5/19/2021
5/22/2021
5/25/2021
5/28/2021
5/31/2021
6/3/2021
6/6/2021
6/9/2021
6/12/2021
6/15/2021
6/18/2021
6/21/2021
6/24/2021
Non-VBA Method
One way this could be done without using VBA is with a INDEX/MATCH formula.
The following formula assumes the data is in B2:F500, the month/years are in A2:A500, the weeks in B1:F1 and the dates to look for are in column N, all on the same sheet Sheet1.
=INDEX($B$2:$F$13,MATCH(TEXT(N1,"yyyy-mmm"),Sheet1!$A$2:$A$13,0),MATCH(INT((DAY(N1)+6)/7),Sheet1!$B$1:$F$1,0))
VBA Method
If you want VBA to do this here's one way.
Option Explicit
Sub findMatchingRecords()
Dim ws As Worksheet
Dim rngData As Range
Dim rngDates As Range
Dim arrData As Variant
Dim arrDates As Variant
Dim arrYearMonth As Variant
Dim arrValues As Variant
Dim arrWeeks As Variant
Dim Res As Variant
Dim idxCol As Long
Dim idxDate As Long
Dim idxRow As Long
Dim wk As Long
Set ws = Sheets("Sheet1")
With ws
Set rngData = .Range("A1").CurrentRegion
Set rngDates = .Range("N1", .Range("N" & Rows.Count).End(xlUp))
End With
With rngData
arrData = rngData.Offset(1, 1).Resize(.Rows.Count - 1, .Columns.Count - 1)
arrYearMonth = .Columns(1).Offset(1).Resize(.Rows.Count - 1)
arrWeeks = .Rows(1).Offset(, 1).Resize(, .Columns.Count - 1)
End With
arrDates = rngDates.Value
ReDim arrValues(1 To UBound(arrDates, 1), 1 To 1)
For idxDate = LBound(arrDates, 1) To UBound(arrDates, 1)
idxRow = 0
idxCol = 0
Res = Application.Match(Format(arrDates(idxDate, 1), "yyyy-mmm"), arrYearMonth, 0)
If Not IsError(Res) Then
idxRow = Res
wk = Int((Day(arrDates(idxDate, 1)) + 6) / 7)
Res = Application.Match(wk, arrWeeks, 0)
If Not IsError(Res) Then
idxCol = Res
End If
End If
If idxRow <> 0 And idxCol <> 0 Then
arrValues(idxDate, 1) = arrData(idxRow, idxCol)
End If
Next idxDate
rngDates.Offset(, 1).Value = arrValues
End Sub
Please, test the next code:
Sub MatchDate_WeekNo()
Dim sh As Worksheet, lastR As Long, arr, arrN, arrfin, i As Long, strDate As String
Dim weekN As Long, arrRow, arrCol, iCol As Variant, iRow As Variant, lastRN As Long
Set sh = Worksheets("Sheet1")
lastR = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
lastRN = sh.Range("N" & sh.Rows.Count).End(xlUp).Row
arr = sh.Range("A1:F" & lastR).Value
arrRow = Application.Index(arr, 1, 0)
arrCol = Application.Transpose(Application.Index(arr, 0, 1))
arrN = sh.Range("N2:N" & lastRN).Value2
ReDim arrfin(1 To UBound(arrN), 1 To 1)
For i = 1 To UBound(arrN)
strDate = StringFromDate(CDate(arrN(i, 1)))
weekN = Int((Day(arrN(i, 1)) + 6) / 7)
iCol = Application.Match(weekN, arrRow, 0)
iRow = Application.Match(strDate, arrCol, 0)
If IsNumeric(iCol) And IsNumeric(iRow) Then
arrfin(i, 1) = arr(iRow, iCol)
End If
Next i
'drop the final array content:
sh.Range("O2").Resize(UBound(arrfin), 1).Value = arrfin
End Sub
Function StringFromDate(d As Date) As String
Dim arrM
Const strMonths As String = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
arrM = Split(strMonths, ",")
StringFromDate = Year(d) & "-" & Application.Index(arrM, Month(d))
End Function
Format(arrDates(idxDate, 1), "yyyy-mmm") does not return the month in case of localization different then English type and only that's why I am using a function...

Array is not considering from the string created in VBA

For some reason, dynamic string created from the specific range is not considering in the array for loops. Below is my code:
Option Explicit
Dim AccrualFile As Workbook, AccrualSht As Worksheet
Dim AccrualFilePath As String
Dim UniqueNames As String, UniqueAccNames As String
Dim Lrows As Long, Lcols As Long
Sub Segregation()
AccrualFilePath = Application.GetOpenFilename(Title:="Please select Accrual Statement")
Set AccrualFile = Workbooks.Open(AccrualFilePath)
Set AccrualSht = AccrualFile.Sheets(1)
Lrows = AccrualSht.Range("B" & Rows.Count).End(xlUp).Row
UniqueNames = Application.WorksheetFunction.TextJoin(""""", """"", True, Application.WorksheetFunction.Unique(AccrualSht.Range("B2:B" & Lrows)))
UniqueAccNames = """""" & UniqueNames & """"""
Dim i As Long
Dim myarr() As Variant
myarr = Array(UniqueAccNames)
For i = LBound(myarr) To UBound(myarr)
Debug.Print myarr(i)
Next
End Sub
Appreciate your help!!
Thank you.
WorksheetFunction.Unique returns a (2D)1 array when passed a Range.
myarr = WorksheetFunction.Unique(AccrualSht.Range("B2:B" & Lrows))
Dim i As Long, j As Long
For i = LBound(myarr, 1) to Ubound(myarr, 1)
For j = Lbound(myarr, 2) to Ubound(myarr, 2)
Debug.Print myarr(i, j)
Next
Next
1 With some exceptions, including:
When the output is a single element, it returns a 1D array.

Fillfdown Approach for an index match function via VBA

with the given code I am trying hard incorporate the Filldown approach until the last row but at present whatever I do only fills row number 1:
Sub FillDownApproach()
Dim destinationWs As Worksheet
Dim destinationLastRow As Long
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
RetVal = destinationWs.Evaluate("INDEX('MyData'!$E:$E,MATCH(1,($A2='MyData'!$B:$B)*(""MyItem""='MyData'!$D:$D),0))")
destinationWs.Range("C2").Value = RetVal
destinationWs.Range("C3: " & "C" & destinationLastRow).FillDown
End Sub
Any suggestion that could point towards the right direction.
Thanks
You cannot do what you want without looping. And Looping ranges is slow.
Instead load Variant arrays and loop them.
Sub FillDownApproach()
Dim destinationWs As Worksheet
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
Dim destinationLastRow As Long
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
Dim lkpArr As Variant
lkpArr = destinationWs.Range("A2:A" & destinationLastRow).Value
With Worksheets("MyData")
Dim retval As Variant
retval = Intersect(.Range("E:E"), .UsedRange)
Dim mtch As Variant
mtch = Intersect(.Range("B:D"), .UsedRange)
End With
Dim outArr As Variant
ReDim outArr(1 To UBound(lkpArr, 1), 1 To 1)
Dim i As Long
For i = 1 To UBound(lkpArr, 1)
Dim j As Long
For j = 1 To UBound(retval, 1)
If mtch(j, 3) = "MyItem" Then
If mtch(j, 1) = lkpArr(i, 1) Then
outArr(i, 1) = retval(j, 1)
Exit For
End If
End If
Next j
Next i
destinationWs.Range("C2").Resize(UBound(outArr, 1), 1).Value = outArr
End Sub

Loop Array from UBound to LBound and check values

I'm trying to create an array, loop from UBound to LBound and check values with the below code.
I 'm receiving an error on line:
If arrPart(i) = strResult Then
Run time error 9
The range I try to import in array:
Code:
Option Explicit
Sub ArrayTest()
Dim LastColumn As Long, CounterPart As Long, i As Long
Dim arrPart As Variant
Dim strResult As String
With ThisWorkbook.Worksheets("Sheet1")
LastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
strResult = "N"
'Set as an array the 4 last matches
arrPart = .Range(Cells(1, LastColumn - 3), Cells(1, LastColumn))
CounterPart = 0
For i = UBound(arrPart) To LBound(arrPart) Step -1
If arrPart(i) = strResult Then
CounterPart = CounterPart + 1
Else
Exit For
End If
Next
End With
End Sub
any suggestions?
Per all the comments above:
Option Explicit
Sub ArrayTest()
Dim LastColumn As Long, CounterPart As Long, i As Long
Dim arrPart As Variant
Dim strResult As String
With ThisWorkbook.Worksheets("Sheet1")
LastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
strResult = "N"
'Set as an array the 4 last matches
arrPart = .Range(.Cells(1, 1), .Cells(1, LastColumn))
CounterPart = 0
For i = UBound(arrPart, 2) To LBound(arrPart, 2) Step -1
If arrPart(1, i) = strResult Then
CounterPart = CounterPart + 1
Else
Exit For
End If
Next
End With
Debug.Print CounterPart
End Sub
Suppose you have a table of cells starting from B4.
This is how you find out the size of the table, transfer the values into an array and iterate through them.
Public Sub ArrayTest()
Dim r_start As Range
Set r_start = Range("B4")
Dim i As Long, n As Long
n = Range(r_start, r_start.End(xlToRight)).Columns.Count
Dim arrPart() As Variant
arrPart = r_start.Resize(1, n).Value
Dim strResult As String
strResult = "N"
Dim counter As Long
counter = 0
For i = 1 To n
If arrPart(1, i) = strResult Then
counter = counter + 1
Else
Exit For
End If
Next i
Debug.Print counter
End Sub

Searching for one list within another

I've written a near-working script to search for a list of words in column B within a larger list in column A.
Sub QualifierArray()
Sub QualifierArray()
Dim List As Worksheet
Set List = Sheets("List")
Dim lastRow As Long
lastRow = (List.Cells(Rows.Count, 1).End(xlUp).Row) 'removed +1
Dim listColumn As Variant
listColumn = List.Range("A1:A" & lastRow)
Dim outputArray As Variant
Dim intQualifier As Long
Dim lastQualifier As Range
ReDim outputArray(1 To lastRow)
Dim i As Long
Dim j As Long
Dim index As Long
index = 1
intQualifier = Range("B" & Rows.Count).End(xlUp).Row
For j = 1 To intQualifier
For i = 1 To lastRow
Set rngQualifier = Range("B" & j)
If InStr(listColumn(i, 1), rngQualifier) > 0 Or InStr(listColumn(i, 1), "[") > 0 Then 'changed = to >
outputArray(index) = listColumn(i, 1)
index = index + 1
End If
Next
Next
End Sub
However, I'm getting a "subscript out of range" for the outputArray. It seems that index has increased to be more than lastRow, which is causing the error. I've tried a variety of fixes, like putting an extra clause like is not empty but to no avail. Does anyone have any suggestions as to what's causing the error? One clue is that removing the Or InStr(listColumn(i, 1), "[") = 0 part` lets the code perfectly (without this clause, of course). Am I getting close to a solution? It feels as if it's not far from here....
Thanks in advance!
try with below code
Sub QualifierArray()
Dim List As Worksheet
Set List = Sheets("List")
Dim lastRow As Long
lastRow = (List.Cells(Rows.Count, 1).End(xlUp).Row) 'removed +1
Dim listColumn As Variant
listColumn = List.Range("A1:A" & lastRow)
Dim outputArray As Variant
Dim intQualifier As Long
Dim lastQualifier As Range
ReDim outputArray(1 To lastRow)
Dim i As Long
Dim j As Long
Dim index As Long
index = 1
intQualifier = Range("B" & Rows.Count).End(xlUp).Row
For j = 1 To intQualifier
For i = 1 To lastRow
Set rngQualifier = Range("B" & j)
If InStr(listColumn(i, 1), rngQualifier) > 0 Or InStr(listColumn(i, 1), "[") > 0 Then 'changed = to >
outputArray(index) = listColumn(i, 1)
index = index + 1
End If
Next
Next
End Sub
Note: Changes made marked in comment

Resources