How to set up an Array formula using Index/match in VBA to get first match cell - excel

I'm trying to set up array formula within a for loop to do a partial match of a string to a list of names on another worksheet called Project Name. This should be the end product I got the formula working in the spreadsheet using the method from exceljet but I ran into an error of "object required" when I tried to covert it to VBA. The cells(i,6) is the location of the string that I am trying to do a partial match to the project names. The column doesn't have to be "6", it is where the Please help. Thanks!
Sub Shortname()
Dim SRng As Variant
Dim SName As Integer
Dim SNrow As Integer
Dim PLcol As Integer
Dim PLrow As Integer
Worksheets(3).Activate
SNrow = Cells(Rows.Count, 1).End(xlUp).Row
SRng = Range(Cells(2, 1), Cells(SNrow, 1)).Value
Worksheets(2).Activate
PLcol = Cells(1, Columns.Count).End(xlToLeft).Column + 1
PLrow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To PLrow
Cells(i, PLcol).Value = Application.WorksheetFunction.Index(SRng, Application.WorksheetFunction.Match("TRUE", Application.WorksheetFunction.IsNumber(Application.WorksheetFunction.Search(SRng.Value, Cells(i, 6))), 0), 1)
Next i
End Sub

Mysterious Variable (SRng)
I would write the code something like this (not the solution just a more readable version):
Sub Shortname()
Dim SRng As Variant
Dim SName As Integer
Dim SNrow As Integer
Dim PLcol As Integer
Dim PLrow As Integer
'Missing Declaration
Dim i As Long
'To avoid jumping around worksheets do NOT use Activate or Select
With Worksheets(3)
SNrow = .Cells(Rows.Count, 1).End(xlUp).Row
SRng = .Range(Cells(2, 1), Cells(SNrow, 1)).Value
End With
With Worksheets(2)
PLcol = .Cells(1, Columns.Count).End(xlToLeft).Column + 1
PLrow = .Cells(Rows.Count, 1).End(xlUp).Row
End With
With Application.WorksheetFunction
For i = 2 To PLrow
'Run-time error 424: Object required
Worksheets(2).Cells(i, PLcol).Value = .Index(SRng, .Match("TRUE", _
.IsNumber(.Search(SRng.Value, Cells(i, 6))), 0), 1)
Next i
End With
End Sub
The error (mystery) lies in the SRng variable. Why is it declared as variant?
If it is a String declare it as String and change the line SRng = .Range(Cells(2, 1), Cells(SNrow, 1)).Value to
SRng = .Range(Cells(2, 1), Cells(SNrow, 1)).Address
If it is a Range object then declare it as Range and remove .Value,
but then you still get the error in the For Next loop since you use SRng.Value in the Search part of the statement, but a range has no value (maybe you wanted to use something like this SRng.Cells(i, 6).Value).
If this doesn't help you provide some more info like a sample of the worksheet(s) to see what's in the cells, ranges ... and explain what it is you're searching for in the For Next loop.

Related

loop from cell i to last cell non-empty cell

As the title says, I want to loop from cell i to the last non-empty cell. But I keep getting a type mismatch error even though I am declaring it the same type.
Dim wsList as Worksheet
Dim wsCode as Worksheet
Dim i as Variant
Dim j as Long
Dim LastCell as Variant
Dim LastCell2 as Long
With wsList
LastCell = .Cells(.Rows.Count, "G").End(xlUp)
LastCell2 = .Cells(.Rows.Count, "F").End(xlUp)
End With
For i = 1 To LastCell
wsList.Range("G2").Offset(i - 1).Copy _
wsCode.Range("C2").Offset((i - 1) * 14)
Next i
For j = 1 To LastCell2
wsCode.Range("F11").Offset((j - 1) * 14).Value = _
wsList.Range("F2").Offset(j - 1).Value
Next j
End Sub
Mismatch error occurs between LastCell and i even though I declared them both as variant. I also tried declaring them as string but still getting the same error. The data type in that particular column is "AB12345" including quotation marks. How can I fix this?
Thanks in advance!
As stated in the comments, you're missing a .row. It would be best to define all your row variables as Long. One other thing to consider is that your method of using end(xlUP) will not account for any rows that are hidden. This answer discusses a variety of ways to address this.
With wsList
LastCell = .Cells(.Rows.Count, "G").End(xlUp).row
LastCell2 = .Cells(.Rows.Count, "F").End(xlUp).row
End With
I think you need to change
Dim LastCell as Variant
To
Dim LastCell as Long
Also, you should clearly identify the sheets for wsList and wsCode.

Convert Excel Array formula into VBA code

I have two set of range named as LIST_KEY and LIST_CAT. In Column A, user will add some data which will contain one of the one of the text from LIST_KEY. I would like to get corresponding Category list from LIST_CAT depends upon the Key value
I am using below VBA code to achieve this. This include a Array formula.
Sub match()
Dim ss As Workbook
Dim test As Worksheet
Set ss = Excel.Workbooks("test.xlsm")
Set test = ss.Worksheets("Sheet1")
For i = 2 To test.Cells(Rows.Count, "A").End(xlUp).Row
Cells(i, "B").FormulaArray = "=INDEX(LIST_CAT,MATCH(TRUE,ISNUMBER(SEARCH(LIST_KEY,RC[-1])),0))"
Cells(i, "B").Formula = Cells(i, "B").Value
Next i
End Sub
This code works perfect if there is less data to fetch. But in my original use case, I will have around 8000 rows. Due to this large number of columns excel will go to not responding state after 2-3 minutes.
Instead of adding Array formula to column B, Is there anyway to convert that into VBA to run this faster. Sorry, I am new to this VBA stuff and dont have much experience
Try the following code, which uses arrays instead of worksheet formulas...
Option Explicit
Sub GetCategories()
Dim sourceWorkbook As Workbook
Set sourceWorkbook = Workbooks("test.xlsm")
Dim sourceWorksheet As Worksheet
Set sourceWorksheet = sourceWorkbook.Worksheets("Sheet1")
Dim lookupArray As Variant
lookupArray = sourceWorkbook.Names("LIST_KEY").RefersToRange.Value
Dim returnArray As Variant
returnArray = sourceWorkbook.Names("LIST_CAT").RefersToRange.Value
Dim tableArray As Variant
Dim lastRow As Long
With sourceWorksheet
lastRow = .Cells(.Rows.Count, "a").End(xlUp).Row
tableArray = .Range("A2:B" & lastRow).Value
End With
Dim desc As String
Dim i As Long
Dim j As Long
For i = LBound(tableArray, 1) To UBound(tableArray, 1)
desc = tableArray(i, 1)
For j = LBound(lookupArray, 1) To UBound(lookupArray, 1)
If InStr(1, desc, lookupArray(j, 1), vbTextCompare) > 0 Then
tableArray(i, 2) = returnArray(j, 1)
Exit For
End If
Next j
Next i
sourceWorksheet.Range("B2").Resize(UBound(tableArray, 1), 1).Value = Application.Index(tableArray, 0, 2)
End Sub

Is it possible to lookup for a value from another sheet in the same workbook?

I have a workbook with multiple spreadsheets. One of the sheets is called "Master Filtered" and the other is called "MTL OR TOR"
I want to fill in the column K of the "Master filtered" sheet with a lookup value from the "MTL or TOR" sheet in the second column. I wrote this piece of code but it is not working.
Sub MTL_OR_TOR()
Dim AcctNb As String
Dim result As String
Worksheets("Master Filtered").Activate
Dim lastrow As Long
lastrow = Cells(Rows.Count, 1).End(xlUp).Row
For G = 4 To lastrow
AcctNb = Cells(G, 3).Value
Set myrange = Worksheets("MTL OR TOR").Range("AA4:AB685") 'Range in which the table MTL or TOR should be entered
result = Application.WorksheetFunction.VLookup(AcctNb, myrange, 2, False)
Range("K" & G).Value = result
Next
End Sub
Do you have any idea why is this code not working and how to fix it?
I was thinking maybe my error is in the line starting with Set myrange= Worksheets("MTL OR TOR") but couldn't figure it out.
Sub MTL_OR_TOR()
' Name your variables in a meaningful way and indicate their type
Dim strAcctNb As String
Dim strResult As String
Dim lngLastRow As Long
Dim lngLoop As Long
Dim rngLookup As Range
'Set your range and variables before you execute the code for readability
Set rngLookup = Worksheets("MTL OR TOR").Range("AA4:AB685") 'Range in which the table MTL or TOR should be entered
'Do not Activate or Select unless you really have to
'Worksheets("Master Filtered").Activate
With Worksheets("Master Filtered")
lngLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
For lngLoop = 4 To lngLastRow
strAcctNb = .Cells(lngLoop, 3).Value
strResult = Application.WorksheetFunction.VLookup(strAcctNb, rngLookup, 2, False)
.Range("K" & lngLoop).Value = strResult
Next
End With
End Sub

Missing, Duplicate declaration in current scope

I'm currently writing a program to analyze some data, and my Debugger is throwing the "Duplicate Declaration in Current Scope" error, highlighting "Dim rTickers As Range". I cannot find a duplicate anywhere in here. Is there some other reason I could be getting this error? Thanks for your time.
Sub TSV_Ticker()
'Create Dictionary To get Unique Values From Column A
Dim dTickers As New Dictionary
Dim i As Long
For i = 2 To Rows.Count
On Error Resume Next
dTickers.Add (Cells(i, 1).Value), CStr(Cells(i, 1).Value)
Next
'Create The Ticker And Sum Column Headers
Range("J1").Value = "<Sum>"
Range("I1").Value = "<Ticker>"
'Define where we will be putting our keys
Dim uTickers As Range
Set uTickers = Range("I2")
'Convert Keys into array for syntax reasons
aTickers = dTickers.Keys
'Resize the range so it will fit the array
Set rTickers = rTickers.Resize(UBound(aTickers), 1)
'Put array into range, verticaly
rTickers.Value = Application.Transpose(aTickers)
'Define Range of column A
Dim rTickers As Range
Set rTickers = Range("A2:A" & ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row)
Dim TSV As Long
'Defining some Date Variables (Column B)
Dim fDate As Integer
Dim eDate As Integer
Dim rDates As Range
Set rDates = Range("B2:B" & ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row)
'And The Open / Close Variables (Colums C&F)
Dim vOpen As Double
Dim Vclose As Double
Dim Delta As Double
Dim pDelta As Double
'Adding Some Columns
sht.Range("J1").EntireColumn.Insert
Range("J1").Value = "Yearly Change"
sht.Range("K1").EntireColumn.Insert
Range("K1").Value = "Percent Change"
For Each Cell In rTickers
'Searching our range that we put the Array in for matching Values
Set t = rTickers.Find(Cell.Value, LookIn:=xlValues, lookat:=xlWhole)
If Not t Is Empty Then
'add column G's value to corresponding I value
Cells(t.Row, 10).Value = Cells(t.Row, 10).Value + Cells(Cell.Row, 7).Value
End If
Next Cell
End Sub
As commented, without using Option Explicit variables are created at the first instance.
So in your code, rTickers is already created when this below line is executed:
Set rTickers = rTickers.Resize(UBound(aTickers), 1)
That being said, below line will give you a compile error:
Dim rTickers As Range
because rTickers variable has already been created.
I'll post this as answer for others reference.
But if Rory or Ashlee wish to add their answers, I'll delete mine :).

Code is refusing to define ranges on activesheets that are not sheet1

I have a listbox on sheet1 with a list of sheetnames. When somebody double clicks on a name in the list, the code is supposed to activate that sheet, select some data and create a graph out of it.
The code is fine, right up until I ask it to define a range on the other sheet. I've had a number of different error messages and as best I can tell, the code is simply refusing to do anything that is not on sheet1. If somebody could explain why, that would be brilliant.
Code: the listbox is called Stocklist
Option Explicit
Sub StockList_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Call stockgraph
End Sub
Private Sub stockgraph()
Application.ScreenUpdating = False
Dim stockrange As Range
Dim daterange As Range
Dim security_name As String
Dim finalrow As Integer
Dim stockarray() As Double
Dim datearray() As String
Dim cell As Range
security_name = Empty
security_name = StockList.Value
If security_name = Empty Then MsgBox ("something's gone wrong, excel doesn't recognise that value") ' DEBUG
Worksheets(security_name).Activate ' --> this bit works fine
finalrow = ActiveSheet.Cells(1, 1).End(xlDown).row ' --> as does this
Set stockrange = Sheets(security_name).Range(Cells(2, 3), Cells(finalrow, 3))
' --> This gives a 1004 error, so does using activesheet
' --> if I don't reference a sheet, despite it not being the activesheet, the ranges are defined on sheet1
' --> and yet, the code was perfectly fine defining finalrow
Set daterange = Sheets(security_name).Range(Cells(2, 1), Cells(finalrow, 1))
ReDim stockarray(1 To finalrow - 1) As Double ' row 1 is a header so 2 to finalrow = 1 to finalrow-1
ReDim datearray(1 To finalrow - 1) As String
For Each cell In stockrange
stockarray(cell.row - 1) = cell.Value
Next cell
For Each cell In daterange
datearray(cell.row - 1) = cell.text
Next cell
Sheets("Top 10 holdings").Activate
' Create graph
Dim c As Chart
Dim s1 As Series
ActiveSheet.Cells(50, 50) = stockarray
ActiveSheet.Shapes.AddChart.Select
Set c = ActiveChart
Set s1 = c.SeriesCollection(1)
c.ChartType = xlLine
s1.Values = stockarray
Application.ScreenUpdating = True
End Sub
You cannot construct a cell range reference in that manner without fully qualifying the internal cell references used as demarcation points.
With Sheets(security_name)
finalrow = .Cells(1, 1).End(xlDown).row
Set stockrange = .Range(.Cells(2, 3), .Cells(finalrow, 3))
Set daterange = .Range(.Cells(2, 1), .Cells(finalrow, 1))
End With

Resources