two criteria of lookup in vba - vba

I want to lookup the value in Columns C of Sheets("MV_Backtest") s.t cell_i match Columns A, cell_j match Columns B, here is the code:
Sub Matrix()
lastRow = ThisWorkbook.Sheets("Sheet2").Cells(Rows.Count, 2).End(xlUp).Row
lastColumn = ThisWorkbook.Sheets("Sheet2").Cells(1,
Columns.Count).End(xlToLeft).Column
For i = 2 To lastRow
For j = 3 To lastColumn
cell_i = ThisWorkbook.Sheets("Sheet2").Cells(i, 2)
cell_j = ThisWorkbook.Sheets("Sheet2").Cells(1, j)
Cells(i, j) = Application.WorksheetFunction.Lookup(1, 0 / (cell_i =
ThisWorkbook.Sheets("MV_Backtest").Columns("A:A")) * (cell_j =
ThisWorkbook.Sheets("MV_Backtest").Columns("B:B")),
ThisWorkbook.Sheets("MV_Backtest").Columns("C:C"))
Next j
Next i
End Sub
Note that each value in one column may not unique, but combining two values, it is unique.
It's ok in the Excel but there is something wrong here?
By the way, how could I set Cells(i, j) = 0 when neither of two conditions match.
Here is the Excel formula:
=LOOKUP(1,0/(I28=I20:I22)*(J28=J20:J22),K20:K22)
cell_i is I28, I20:I22 is Columns A, cell_j is J28, J20:J22 is Columns B, K20:K22 is Columns C.

(cell_i = ThisWorkbook.Sheets("MV_Backtest").Columns("A:A")) * (cell_j = ThisWorkbook.Sheets("MV_Backtest").Columns("B:B"))
While the above code looks correct for an Excel formula, it is not valid VBA. In Excel it generates and multiples two arrays, but you cannot generate an array like that in VBA (VBA does not allow array multiplication, array comparison, etc).
If you have a valid Excel formula, you can let Excel evaluate it then get the result. Two ways to do that:
1- Using Application.Evaluate:
Cells(i, j).value = Application.Evaluate("=Lookup(1,0/((" & cell_i & _
"= MV_Backtest!A:A) * (" & cell_j &_
"=MV_Backtest!B:B)), MV_Backtest!C:C)")
2- Using .Formula
Cells(i, j).Formula = "=Lookup(1,0/((" & _
cell_i & "=MV_Backtest!A:A) * (" & _
cell_j & "=MV_Backtest!B:B)), MV_Backtest!C:C)"
If you want after then to fix the value and remove the formula, you can:
Cells(i, j).Value = Cells(i, j).Value2
EDIT:
To set a cell to zero when no match exists, the usual way is the enclose the formula with IFERROR(myformula, 0). Hence, for example:
Cells(i, j).value = Application.Evaluate("=IFERROR(Lookup(1,0/((" & cell_i & _
"= MV_Backtest!A:A) * (" & cell_j &_
"=MV_Backtest!B:B)), MV_Backtest!C:C)), 0")
Or, you can check (in VBA) if the resulting value of the initial formula is an error code. i.e.
If IsError(Cells(i, j).Value) Then Cells(i, j).Value = 0

Related

Edit value of cells in a specific column if a condition is not met using Excel VBA

I need a macro that will apply the below-mentioned formula in column J if the value of a cell in column C is "Hits_US" and the value of a cell in column D is "harry". Below is the formula
=((Column G*32)+(Column H*28)+300)/60
Please note that there will be other values in column J. So, only if the condition is met, the formula has to be applied.
I tried to do this in parts. I first tried to multiply the value in column G by 32. But it did not work.
For i = 1 To 10
If Sheets(1).Range("C" & i).Value = "Hits_US" And Range("D" & i).Value <> "harry" Then
Cells(i, 10) = Cells(i, 7) * 32
End If
Next i
You should be able to avoid a loop
Sheets(1).Range("J1:J10").Formula = "=IF(AND(C1=""Hits_US"",D1=""Harry""),(G1*32+H1*28+300)/60,"""")"
For all rows in J, based on how many entries are in column C
With Sheets(1)
.Range("J1:J" & .Range("C" & Rows.Count).End(xlUp).Row).Formula = "=IF(AND(C1=""Hits_US"",D1<>""Harry""),(G1*32+H1*28+300)/60,"""")"
End With
If you want to leave a formula in cells then I'd go with R1C1 notation:
Sheets(1).Range("J1:J10").FormulaR1C1 = "=IF(AND(RC3=""Hits_US"",RC4=""harry""),(RC7*32+RC8*28+300)/60,"""")"
While if you want to leave only the formula results then you have to possibilities:
have formulas do the math and then leave only values
With Sheets(1).Range("J1:J10")
.FormulaR1C1 = "=IF(AND(RC3=""Hits_US"",RC4=""harry""),(RC7*32+RC8*28+300)/60,"""")"
.Value = .Value
End With
have VBA do the math and write its results directly
With Sheets(1)
For i = 1 To 10
If .Range("C" & i).Value = "Hits_US" And .Range("D" & i).Value = "harry" Then
.Cells(i, 10) = (.Cells(i, 7) * 32 + .Cells(i, 8) * 28 + 300) / 60
End If
Next
End With

Excel data from colum to row

I have data like in the picture below:
I need to (with a macro) arrange the data so that every row with a number after ELEVATION\AZIMUTH be in the first row, like in picture:
I have a lot of rows like this data. Maybe any one can help?
This is not tested. you can give it a try. the below can be written in diff way as well.
Sub test1()
Dim LastRow, DataCount, temp As Double
i = 1
LastRow = 1
Do While LastRow <> 0
Range("A" & i).Select
If ActiveCell.Value = "ELEVATION\AZIMUTH" Then
'Cut all three row and paste
DataCount = Application.WorksheetFunction.CountA(Range(i & ":" & i))
Range("A" & ActiveCell.Row + 1, "I" & ActiveCell.Row + 1).Cut ActiveCell.Offset(0, DataCount)
Range("A" & ActiveCell.Row + 2, "I" & ActiveCell.Row + 2).Cut ActiveCell.Offset(0, DataCount * 2)
Range("A" & ActiveCell.Row + 3, "I" & ActiveCell.Row + 3).Cut ActiveCell.Offset(0, DataCount * 3)
Else
LastRow = Application.WorksheetFunction.CountA(Range("A" & i, "A" & i + 10))
End If
i = i + 1
Loop
End Sub
This can also be done without the use of macros.
I am assuming your last column where data is there is column I and the row number is 11. You want to fill all cells in row 11 after column I, i.e. J11,K11.... with values right below I11
You could do this, paste in J11
J11=INDEX($I$11:$I$1000,COLUMN(B1),1)
Drag the formula across the row and you should get your desired output

VBA Issue with nested do whiles and nested ifs

I have four columns, loop over two of the columns using nested do while loops, and then two if statements to act as constraints. If the two if statements are passed, revalue (paste is an option too), two new cells to the values of the cells that were checked using the index on the first loop, and another two new cells to the values of the cells that were checked using the index on the nested loop.
code:
Dim i
Dim j
i = 1
j = 1
Do Until IsEmpty(Range("BE" & i))
Do Until IsEmpty(Range("BH" & j))
If Cells(i, "BE").Value = Cells(j, "BH").Value Then
If (Cells(j, "BG").Value - Cells(i, "BF")) < TimeValue("1:00:00") Then
'This is not correctly filtering, dates/time are in
' mm/dd/yy hh:mm format
Range("BJ" & i).Value = Range("BE" & i).Value
Range("Bk" & i).Value = Range("BF" & i).Value
Range("BL" & i).Value = Range("BG" & j).Value
Range("BM" & i).Value = Range("BH" & j).Value
End If
End If
j = j + 1
Loop
i = i + 1
j = 1
Loop
End Sub
What it does:
It does almost everything correctly. The issue is that it does NOT correctly check if the difference in time between cells BG(j) and BF(i) < 60 minutes. Whether using:
If (Cells(j, "BG").Value - Cells(i, "BF")) * 1440 < 60 Then
or
IF (Cells(j, "BG").Value - Cells(i, "BF")) < TimeValue("1:00:00") Then
values that are 5 hours in difference are being seen as true and passing through the if statement.
Try adding j = 1 just after i = i + 1

Remove / Filter Cell Contents in Microsoft Excel 2013

I am looking for the best way to clean up the cell contents of one particular cell in my spreadsheet. As it exists now, Column D lists a City, State, and High School in the same cell (Screenshot #1). I need to split these values out into 3 unique columns/cells as shown in Screenshot #2. How would I accomplish this?
** Note - The example below is just a sample size. I have thousands of cells to perform this on.
Existing cell format:
New Format (Hopefully):
Use Text-to-Columns "delimited" to split on the comma, then use it again "fixed width" to split the state from the school name (assuming the state is always 2 characters). Clean up spaces with TRIM if required.
Hi something like this should look through all your cells in row D and return the values you are looking for in the next 3 columns; might need a little adjusting
For each cell in Range("D2:D & Range("D2".End(xlDown).Row))
cell.offset(columnOffset:=1) = left(cell,instr(String1:=cell, String2:= ","))
cell.offset(columnOffset:=2) = Mid(cell,instr(String1:=cell, String2:= ",")+1,2)
cell.offset(columnOffset:=3) = right(cell,len(cell)-instr(String1:=cell, String2:= ",")+3)
Next
I tried Jake Duddy's code it contains quite some errors, I do not know if it works. At the same time you can try below code.
Dim LastRow As Long
Dim State_L As String
Dim City_L As String
Dim HS_L As String
LastRow = Range("D" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
City_L = Left(Range("D" & i), InStr(1, Range("D" & i), ",") - 1) ' Getting up to comma
State_L = Mid(Range("D" & i), InStr(1, Range("D" & i), ",") + 1, 2) 'Getting after comma for 2 characters
HS_L = Mid(Range("D" & i), InStr(1, Range("D" & i), ",") + 3, Len(Range("D" & i)) - InStr(1, Range("D" & i), ",")) 'Getting after comma+2 characters upto the end
Range("E" & i).Value = City_L
Range("F" & i).Value = State_L
Range("G" & i).Value = HS_L
Next
Select the cells you wish to process and run this small macro:
Sub ParseData()
Dim r As Range, L As Long, L1 As Long, L2 As Long
For Each r In Selection
t = r.Text
L = Len(t)
L1 = InStr(1, t, ",")
For i = 1 To L
If r.Characters(i, 1).Font.Italic = True Then
L2 = i
Exit For
End If
Next i
r.Offset(0, 1).Value = Mid(t, 1, L1 - 1)
r.Offset(0, 2).Value = Mid(t, L1 + 1, L2 - L1 - 1)
r.Offset(0, 3) = Mid(t, L2)
r.Offset(0, 3).Font.Italic = True
Next r
End Sub
For example:

How to execute a function in the cell on the right of every row of a specific range?

Earlier i was trying to sum every column of a range in the cell right below and got successfully helped. I'm just trying to modify the code i received to do the same for every row and get the result in the column just on the right
Sub miine()
Dim a, i As Integer, Data, sums As Range
a = InputBox("How many cells for the square?")
Set Data = Range(ActiveCell.Offset(0, 0), ActiveCell.Offset(a - 1, a - 1))
Set sums = Range(ActiveCell.Offset(a, 0), ActiveCell.Offset(a, a - 1))
For Each cell In sums
cell.Value = "=SUM(" & Split(cell.Address, "$")(1) & cell.Row - a & ":" & Split(cell.Address, "$")(1) & cell.Row - 1 & ")"
Next
Set sum = Range(ActiveCell.Offset(0, a), ActiveCell.Offset(a - 1, a))
For each cell in sum
cell.Value = "=SUM(" & cell.Column - a & Split(cell.Address, "$")(2) & ":" & cell.Column - 1 & Split(cell.Address, "$")(2) & ")"
End Sub
The second part doesn't work, i get the sum in place on the right, but the range selected for the sum appears like that Range(11:41) instead of Range("A1:D1"). Thanks in advance
The Cell.Address is something like this: "$A$1"; the function Split is splitting by the symbol $ so the letter A will be contained at position (1) of the array while the row number 1 at the position (2). That's why your:
Split(cell.Address, "$")(2)
is returning a number and not a letter. What you want to do is probably:
Set sum = Range(ActiveCell.Offset(0, a), ActiveCell.Offset(a - 1, a))
For each cell in sum
cell.Value = "=SUM(" & Split(cell.Offset(0,-a).Address,"$")(1) & cell.Row & ":" & Split(cell.Offset(0,-1).Address,"$")(1) & cell.Row & ")"
Next cell