I struggle with VBA and have spent a few days trying to find a solution to this problem. Essentially, I have two spreadsheets with large sets of data. Column K of "Design Mods" worksheet contains the same types of values as Column C of the "Output" Worksheet. I've been trying to get my script to do the following:
1. for each cell in column k of "Design Mods", check if there is a matching cell in column c of the "output" spreadsheet
2. if a match is found, then populate the cell in "Design Mods" to columns over with the information from column b of "Output"
Because of my lack of experience, I've only been able to setup the script below which only checks and pulls correctly for one cell.
I need it to check each cell against a range of other cells.
Any help/guidance would be very much appreciated.
Thank you very much!
Sub MatchValue_Test()
'Routine is meant to populate columns "Design Mods" Spreadsheet with affected calculations from the "Output" Spreadsheet
'Variables below refer to Design Mods spreadsheet
Dim designmod As Worksheet '<-- Design Mods worksheet that we are comparing to the Output Data
Dim DesignMod_DClrow As Integer '<-- Variable used to count to the last low in the DC Number Column of Design Mods Spreadsheet
Dim designmoddc As Range '<-- Variable used to identify the range of values being checked in Design Mods is the DC Numbers Column K from K4 to the end of the column
Dim valuetofind As String '<-- DC Number used as matching criteria between Design Mods spreadsheet and Output Data
'Test Variables for integrating references to from Output worksheet
Dim testset As Worksheet
Dim test2_lrow As Integer
Dim test As Range
Dim valuetofindw2 As String
'Variables below pertain the routine itself
Dim found As Boolean '<-- this condition has to be false to start the routine
'Start of Routine
found = False
'Definition of Data Ranges in Design Mods spreadsheet
Set designmod = ActiveWorkbook.Worksheets("Sheet1")
DesignMod_DClrow = designmod.Range("K4").End(xlDown).Row
Set designmoddc = designmod.Range("K4:K" & DesignMod_DClrow)
'Test variables for integrating values from Output worksheet
Set testset = ActiveWorkbook.Worksheets("Sheet2")
test2_lrow = testset.Range("C2").End(xlDown).Row
Set test = testset.Range("C2:C" & test2_lrow)
'Identify the value being matched against
valuetofind = designmod.Range("L4").Value '<-- the script wont run if I have this value set to a range, and I need to figure out get this to loop so I don't need a variable for every cell im checking against
'test variables to figure out if statement
valuetofindw2 = testset.Range("C2").Value
valuetofindw3 = testset.Range("B2").Value
valuetofindw4 = designmod.Range("K4")
'If Statements performing the comparison
For Each Cell In designmoddc
If Cell.Value = valuetofindw3 Then
found = True
End If
Next
If found = True Then
designmoddc.Cells.Offset(0, 2).Value = testset.Range("B2")
End If
End Sub
You did not answer my clarification questions...
I prepared a solution, able to work very fast (using arrays). Please back-up your workbook, because the code will rewrite the matching cases in column M:M.
Sub MatchValue_TestArrays()
Dim designMod As Worksheet, lastRowD As Long, testSet As Worksheet, lastRowT As Long
Dim arrDes As Variant, arrTest As Variant, d As Long, t As Long, boolFound As Boolean
Set designMod = Worksheets("Sheet1")
Set testSet = Worksheets("Sheet2")
lastRowD = designMod.Range("K" & Cells.Rows.Count).End(xlUp).Row
lastRowT = testSet.Range("C" & Cells.Rows.Count).End(xlUp).Row
arrDes = designMod.Range("K4:M" & lastRowD).value 'load the range in array
arrTest = testSet.Range("B2:C" & lastRowT).value
For d = 1 To UBound(arrDes, 1)
For t = 1 To UBound(arrTest, 1)
If arrDes(d, 1) = arrTest(t, 2) Then
arrDes(d, 3) = arrTest(t, 1)'fill the array third column (M:M) with values of B:B testSheet...
Exit For
End If
Next t
Next d
designMod.Range("K4:M" & lastRowD).value = arrDes' Drop the modified array
End Sub
Try the updated code, please. It searches now for all occurrences and put each one in a consecutive column:
Sub MatchValue_TestArrays_Extended()
Dim designMod As Worksheet, lastRowD As Long, testSet As Worksheet, lastRowT As Long
Dim arrDes As Variant, arrTest As Variant, d As Long, t As Long, col As Long
Set designMod = Worksheets("Design") ' Worksheets("Sheet1")
Set testSet = Worksheets("TestS") ' Worksheets("Sheet2")
lastRowD = designMod.Range("K" & Cells.Rows.Count).End(xlUp).Row
lastRowT = testSet.Range("C" & Cells.Rows.Count).End(xlUp).Row
arrDes = designMod.Range("K4:AQ" & lastRowD).value
arrTest = testSet.Range("B2:C" & lastRowT).value
For d = 1 To UBound(arrDes, 1)
col = 3 'the column where the occurrence will be put
For t = 1 To UBound(arrTest, 1)
If arrDes(d, 1) = arrTest(t, 2) Then
arrDes(d, col) = arrTest(t, 1): col = col + 1
End If
Next t
Next d
designMod.Range("K4:AQ" & lastRowD).value = arrDes
End Sub
Using Match() is fast when your data is on a worksheet:
Sub MatchValue_Test()
Dim wsDesign As Worksheet, wsOut As Worksheet, m, c As Range
Set wsDesign = ActiveWorkbook.Worksheets("Sheet1")
Set wsOut = ActiveWorkbook.Worksheets("Sheet2")
For Each c In wsDesign.Range(wsDesign.Range("K4"), _
wsDesign.Cells(Rows.Count, "k").End(xlUp)).Cells
m = Application.Match(c.Value, wsOut.Columns("C"), 0)
If Not IsError(m) Then
'if Match() found a hit then m will be the row number on sheet2
c.Offset(0, 2).Value = wsOut.Cells(m, "B").Value
End If
Next c
End Sub
Related
Is anyone can help me, pls take a look at the picture i attached.
I want to compare 2 pair of data from 2 different excel file, Station (left file column B) with Station (right file column A) AND Time (left file row 1) with Tendancy (right file Column F).
The left file is the report that im about to finished, the right file is the reference data. If the station and the time data is match each other, it will filled with "1", if not it will stay empty.
The data will start filling from cell C2 until Z32. Im stuck with FOR and IF looping i used. And here's the example:
Cell C2 will filed with "1" bcs there is station 2000001 (cell A2) at 00UTC (cell F2) on the right file.
Cell E2 will stay empty bcs there is station 2000001 BUT NOT at 02UTC on the right file.
Cell C3 will stay empty bcs there is station 2000002 BUT NOT at 00UTC on the right file.
Dim countSM As Long
Dim countSS As Long
Dim countWM As Long
Dim countWS As Long
Dim resultCol As Long
Dim resultRow As Long
Dim lastSM As Long
Dim lastSS As Long
Dim lastWM As Long
Dim lastWS As Long
Dim lastRCol As Long
Dim lastRRow As Long
lastSM = wb1.Sheets("Sheet1").Cells(Rows.count, 1).End(xlUp).Row
lastSS = wb2.Sheets("Worksheet").Cells(Rows.count, 1).End(xlUp).Row
lastWM = wb1.Sheets("Sheet1").Cells(1, Columns.count).End(xlToLeft).Column
lastWS = wb2.Sheets("Worksheet").Cells(Rows.count, 1).End(xlUp).Row
lastRCol = wb1.Sheets("Sheet1").Cells(1, Columns.count).End(xlToLeft).Column
lastRRow = wb1.Sheets("Sheet1").Cells(Rows.count, 1).End(xlUp).Row
For countSM = 2 To lastWM
For countSS = 2 To lastWS
If wb1.Sheets("Sheet1").Cells(countSM, "B") = wb2.Sheets("Worksheet").Cells(countSS, "A") Then
For countWM = 3 To lastWM
For countWS = 2 To lastWS
If wb1.Sheets("Sheet1").Cells(1, countWM) = wb2.Sheets("Worksheet").Cells(countWS, "F") Then
For resultRow = 2 To lastRRow
For resultCol = 3 To lastRCol
wb1.Sheets("Sheet1").Cells(resultRow, resultCol) = "1"
Next resultCol
Next resultRow
Next countSS
ElseIf wb1.Sheets("Sheet1").Cells(1, countWM) <> wb2.Sheets("Worksheet").Cells(countWS, "F") Then
wb1.Sheets("Sheet1").Cells(resultRow, resultCol) = ""
Next countWM
End If
Next countSS
ElseIf wb1.Sheets("Sheet1").Cells(countSM, "B") <> wb2.Sheets("Worksheet").Cells(countSS, "A") Then
wb1.Sheets("Sheet1").Cells(resultRow, resultCol) = ""
Next countSM
End If
I made a code that may work for you. Just count how many rows got the station and UTC value you want to check. If the answer is zero, leave the cell empty. If not, then return 1.
My code is designed on same workbook but it can be adapted yo work with 2 different workbooks easily.
My fake dataset:
My code:
Sub test()
'<------>
'
'
'
'
'YOUR CODE TO OPEN BOTH FILES
'
'
'
'<---->
Dim LeftSheet As Worksheet
Dim RightSheet As Worksheet
Dim MyData As Range 'range to store the data (right file)
Dim LR As Long 'Last row of left file, column Station
Dim LC As Long 'Lastcolumn of left file, (whatever UTC it is)
Dim i As Long
Dim zz As Long
Dim MiF As WorksheetFunction
Set MiF = WorksheetFunction
Dim MyStation As String
Dim MyUTC As String
'Probably you'll need just to adjust references to worksheets from different workbooks
Set LeftSheet = ThisWorkbook.Worksheets("Destiny")
Set RightSheet = ThisWorkbook.Worksheets("Source")
'we store all data into array
Set MyData = RightSheet.Range("A1").CurrentRegion
'data starts at index 2, and we want data from columns 1 and 6 on the range
'Columns 1 and 6 mean columns A and F
'I guess maybe you'll need to adapt this too.
With LeftSheet
LR = .Range("B" & .Rows.Count).End(xlUp).Row
LC = .Cells(1, .Columns.Count).End(xlToLeft).Column
'we count how many rows got the station and tendancy value (intersection) on the right file
' if the count is 0, do nothing. If not zero, return 1 on the cell
'our references will be always at column 2 and row 1
For i = 2 To LR Step 1 'we start at row 2 on left file
MyStation = .Range("B" & i).Value
For zz = 3 To LC Step 1 'we start at column 3, that means column C
MyUTC = .Cells(1, zz).Value
If MiF.CountIfs(MyData.Columns(1), MyStation, MyData.Columns(6), MyUTC) <> 0 Then .Cells(i, zz).Value = 1
Next zz
Next i
End With
'clean variables
Set MyData = Nothing
Set LeftSheet = Nothing
Set RightSheet = Nothing
End Sub
Output after executing code:
Give this solution a try:
Option Explicit
Private Type TWorksheetData
WrkSheet As Worksheet
LastRow As Long
LastColumn As Long
End Type
Sub CopyCompare()
'Organize the variables by referenced worksheet
Dim worksheetData As TWorksheetData
Dim sheet1Data As TWorksheetData
'your solution will provide separate Workbooks for the code below
'ActiveWorkbook (in my case) had both worksheets in order to develop the solution
sheet1Data = SetupWorksheetData(Application.ActiveWorkbook, "Sheet1", sheet1Data)
worksheetData = SetupWorksheetData(Application.ActiveWorkbook, "Worksheet", worksheetData)
Dim refData As Dictionary
Set refData = New Dictionary
'Load the reference data (key = station, value = collection of UTCs)
Dim station As Long
Dim countRow As Long
For countRow = 2 To worksheetData.LastRow
station = CLng(worksheetData.WrkSheet.Range("A" & CStr(countRow)).Value)
If Not refData.Exists(station) Then
refData.Add station, New Collection
End If
refData(station).Add worksheetData.WrkSheet.Range("F" & CStr(countRow)).Value
Next countRow
'Load the UTC header columns from Sheet1
Dim outputMap As Dictionary '(key = UTCXX, value = column Number)
Set outputMap = LoadUTCHeaderColumns(sheet1Data)
'Operate on the Sheet1 data to set the value
For countRow = 2 To sheet1Data.LastRow
station = CLng(sheet1Data.WrkSheet.Range("B" & CStr(countRow)).Value)
Dim utcRef As Variant
If refData.Exists(station) Then
Dim utc As Variant
For Each utc In refData(station)
If InputSheetHasUTCEntry(utc, outputMap) Then
sheet1Data.WrkSheet.Cells(countRow, outputMap(utc)) = "1"
End If
Next
End If
Next countRow
End Sub
Private Function InputSheetHasUTCEntry(ByVal utc As String, ByVal outputMap As Dictionary) As Boolean
InputSheetHasUTCEntry = False
Dim utcRef As Variant
For Each utcRef In outputMap.Keys
If utc = utcRef Then
InputSheetHasUTCEntry = True
Exit Function
End If
Next utcRef
End Function
Private Function LoadUTCHeaderColumns(ByRef sheetData As TWorksheetData) As Dictionary
Set LoadUTCHeaderColumns = New Dictionary
Dim columnHeader As String
Dim outputCol As Long
For outputCol = 1 To sheetData.LastColumn
columnHeader = sheetData.WrkSheet.Cells(1, outputCol).Value
If InStr(columnHeader, "UTC") > 0 Then
LoadUTCHeaderColumns.Add columnHeader, outputCol
End If
Next outputCol
End Function
Private Function SetupWorksheetData(ByVal wb As Workbook, ByVal sheetName As String, ByRef wrksheetData As TWorksheetData) As TWorksheetData
SetupWorksheetData = wrksheetData
Set SetupWorksheetData.WrkSheet = wb.Sheets(sheetName)
SetupWorksheetData.LastRow = SetupWorksheetData.WrkSheet.Cells(Rows.Count, 1).End(xlUp).Row
SetupWorksheetData.LastColumn = SetupWorksheetData.WrkSheet.Cells(1, Columns.Count).End(xlToLeft).Column
End Function
Solution comments:
Loads static reference data from from sheet Worksheet (recommend a different sheet name)
Loads static column number information from Sheet1
There are lots of variables holding similar data for each worksheet used. This indicates an opportunity for using a UserDefinedType (TWorksheetData in this case). This organizes and reduces the number of variables to declare and track.
#1 and #2 uses a Dictionary to retain and correlate static information (requires adding a reference to the Microsoft Scripting Runtime).
Other comments:
(Best Practice) Always declare Option Explicit at the top of modules. Forces all variables used to be declared.
(Best Practice) Don't Repeat Yourself (DRY) - there is a lot of repeated expressions in the original code. This is especially important with Strings. More could be done with the solution provided, but (for example) you will notice that the worksheet name strings only appear once.
I'm trying to figure out the best way to attack this problem and my head is spinning a bit, I'm not sure if I should use For Each Cell or Arrays or Collections to do some comparisons and copy entire rows to new sheets. I'd like to use Arrays but my code only uses the values of column but then I have to go back and re-loop through column to find "missing values" and copy entire row which seems to defeat part of the point of using arrays (speed/efficiency).
I'm looking for advice on the best way to tackle this issue, but I'll post my array code as well.
First off, example data:
Sheet1:
Sheet2:
The idea is Sheet1 is yesterdays report and sheet2 is todays.
My goal is two more sheets (or one combo sheet, but that seems unnecessary hard as I need to do total calculations on each result sheet search results respectively by totaling one of the columns, but not the value in column A)
ItemsAdded:
A6 AV6
ItemsRemoved:
A5 AV5
So basically it is finding what items where removed and what was added comparing sheet2 to sheet1 column A.
So far I was able to get that part, without the row values and I'm really wondering if I'm attacking this correctly.
IE: This gets the missing/added items. Now I need to go and fetch the entire row for the values in each sheet, but am unsure how and the code is starting to look long and repeating.
Public Function RangeToArray(Rng As Range) As Variant
Dim i As Long, r As Range
ReDim arr(1 To Rng.Count)
i = 1
For Each r In Rng
arr(i) = r.Value
i = i + 1
Next r
RangeToArray = arr
End Function
Public Sub Compare_Columns_A_and_B_with_Arrays()
Dim wb As Workbook, wsA As Worksheet, wsB As Worksheet, Missing As Worksheet, Added As Worksheet
Set wb = ActiveWorkbook
Set wsA = wb.Worksheets("Sheet1")
Set wsB = wb.Worksheets("Sheet2")
Set Missing = wb.Worksheets("Missing")
Set Added = wb.Worksheets("Added")
Dim lRowA As Long
lRowA = wsA.Cells(Rows.Count, 1).End(xlUp).Row
Dim sourceArray As Variant, srcrng As Range
Set srcrng = wsA.Range("A1:A" & lRowA)
sourceArray = RangeToArray(srcrng)
Dim lRowB As Long
lRowB = wsB.Cells(Rows.Count, 2).End(xlUp).Row
Dim verifyArray As Variant, verifyrng As Range
Set verifyrng = wsB.Range("A1:A" & lRowB)
verifyArray = RangeToArray(verifyrng)
For Each arrval In sourceArray
IsInArray = (UBound(Filter(verifyArray, arrval)) > -1)
If IsInArray = False Then
'Debug.Print arrval
Dim lRowMissing As Long
lRowMissing = Missing.Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Missing.Range("A" & lRowMissing).Value = arrval
End If
Next arrval
For Each arrval In verifyArray
IsInArray = (UBound(Filter(sourceArray, arrval)) > -1)
If IsInArray = False Then
'Debug.Print arrval
Dim lRowAdded As Long
lRowAdded = Added.Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Added.Range("A" & lRowAdded).Value = arrval
End If
Next arrval
End Sub
Assuming that you want to achieve something like this:
In a Sheet1 and Sheet2 there are headers (in my case i've used Header 1 and Header 2.
In a result sheet:
Yesterday column holds an information about count of A(x) data in Sheet1.
Today column holds an information about count of A(x) data in Sheet2.
I have used below code:
Option Explicit
Sub CompareData()
Dim wbk As Workbook
Dim wshYesterday As Worksheet, wshToday As Worksheet, wshResult As Worksheet
Dim i As Integer, j As Integer, k As Integer
On Error Resume Next
Set wbk = ThisWorkbook
Set wshResult = wbk.Worksheets("Result")
On Error GoTo Err_CompareData
If Not wshResult Is Nothing Then
Application.DisplayAlerts = False
wbk.Worksheets("Result").Delete
Application.DisplayAlerts = True
End If
Set wshYesterday = wbk.Worksheets("Sheet1")
Set wshToday = wbk.Worksheets("Sheet2")
Set wshResult = wbk.Worksheets.Add(After:=wshToday)
wshResult.Name = "Result"
wshResult.Range("A1") = "Header 1"
wshResult.Range("B1") = "Header 2"
wshResult.Range("C1") = "Yesterday"
wshResult.Range("D1") = "Today"
'find last entry in yesterdays data
i = wshYesterday.Range("A" & wshYesterday.Rows.Count).End(xlUp).Row
j = 2
'copy into result sheet
wshYesterday.Range("A2:B" & i).Copy wshResult.Range("A" & j)
j = j + i - 1
'find last entry in todays data and copy into result sheet
i = wshToday.Range("A" & wshToday.Rows.Count).End(xlUp).Row
wshToday.Range("A2:B" & i).Copy wshResult.Range("A" & j)
'remove duplicates
i = wshResult.Range("A" & wshResult.Rows.Count).End(xlUp).Row
wshResult.Range("A2:B" & i).RemoveDuplicates Columns:=Array(1, 2), Header:=xlNo
j = 2
i = wshResult.Range("A" & wshResult.Rows.Count).End(xlUp).Row
Do While j <= i
'count values stored in column #1 in yesterdays data
k = Application.WorksheetFunction.CountIf(wshYesterday.UsedRange, wshResult.Range("A" & j))
wshResult.Range("C" & j) = k
'count todays data
k = Application.WorksheetFunction.CountIf(wshToday.UsedRange, wshResult.Range("A" & j))
wshResult.Range("D" & j) = k
j = j + 1
Loop
Exit_CompareData:
On Error Resume Next
Set wshYesterday = Nothing
Set wshToday = Nothing
Set wshResult = Nothing
Set wbk = Nothing
Exit Sub
Err_CompareData:
MsgBox Err.Description, vbExclamation, Err.Number
Resume Exit_CompareData
End Sub
Feel free to improve it to your needs.
Hard to know exactly what you want, but here is a Power Query solution (available in Excel 2010+) that creates a table summarizing what's been removed and/or added.
I assumed your data was in tables named Yesterday and Today. Change the table names in the Source = lines to match your real data.
M-Code
let
//Read in the data tables
Source = Excel.CurrentWorkbook(){[Name="Yesterday"]}[Content],
Yesterday = Table.TransformColumnTypes(Source,{{"Column1", type text}, {"Column2", type text}}),
Source2 = Excel.CurrentWorkbook(){[Name="Today"]}[Content],
Today = Table.TransformColumnTypes(Source2,{{"Column1", type text}, {"Column2", type text}}),
/*Using the appropriate JoinKind, create two different tables for
itemsAdded and itemsRemove*/
itemsAddedTBL = Table.NestedJoin(Today,"Column1",Yesterday,"Column1","TBL",JoinKind.LeftAnti),
//Remove the unneeded TBL column
itemsAdded = Table.RemoveColumns(itemsAddedTBL,"TBL"),
//Add a column stating "Added"
itemsAddedLBL = Table.AddColumn(itemsAdded,"Add/Remove", each "Added", type text),
//Repeat the above for removed items
itemsRemovedTBL = Table.NestedJoin(Yesterday,"Column1",Today,"Column1","TBL",JoinKind.LeftAnti),
itemsRemoved = Table.RemoveColumns(itemsRemovedTBL,"TBL"),
itemsRemovedLBL = Table.AddColumn(itemsRemoved, "Add/Remove", each "Removed",type text),
//combine (append) the two tables into one
comb = Table.Combine({itemsAddedLBL,itemsRemovedLBL})
in
comb
I actuallaly ended up using #AceErno's comment and using AutoFilter to pull the EntireRows of the data that was found by comparing arrays using the code in my original question. I'm not sure happy with my code, but it works and I can look into that later when I am feeling up for it.
Pretty basic question here but my VBA skills are pretty rusty. I have two worksheets where a machine just dumps data into them. Each sheet is just one column and SheetA has ~250 rows and SheetB has ~1300 rows. So what I need to do is compare the first value in sheetA to every value in sheetB, if a match is found I need to copy it to another sheet (SheetC) and then move to the next value in SheetA and repeat this till every value in SheetA has been compared to every value in SheetB. I think the best way to do this is with arrays but I cannot for the life of me remember how to do the actual comparison. Below is the code calling up the sheets and arrays I think....any help is appreciated!
Dim SheetA As Variant
Dim SheetB As Variant
Dim RangeToCheckA As String
Dim RangeToCheckB As String
'Get the worksheets from the workbooks
Set wbkA = Workbooks.Open(Filename:="H:\Chelsea QE\CD6\Evan West\OSM37 with locations 9-30-19.xls")
Set SheetA = wbkA.Worksheets("OSM37")
Set wbkB = Workbooks.Open(Filename:="H:\Chelsea QE\CD6\Evan West\New folder\Flat Rock and Roush VIN Tracker U625 - U611 Lower control arm welds.xlsx")
Set SheetB = wbkB.Worksheets("Master VIN")
'This is the range in SheetA
RangeToCheckA = "B2:B239"
'This is the range in SheetB
RangeToCheckB = "B4:B1339"
SheetA = SheetA.Range(RangeToCheckA)
SheetB = SheetB.Range(RangeToCheckB)
Without changing much of your code and adding a call to a custom function, you could do the following:
Private Sub CompareWorkBooks()
Dim wbkA As Workbook, wbkB As Workbook
Dim SheetA As Worksheet, SheetB As Worksheet, SheetC As Worksheet
Dim RangeToCheckA As String
Dim RangeToCheckB As String
Dim arrySheetA() As Variant, arrySheetB() As Variant, _
arryOut() As Variant
'Get the worksheets from the workbooks
Set wbkA = Workbooks.Open(Filename:="H:\Chelsea QE\CD6\Evan West\OSM37 with locations 9-30-19.xls")
Set SheetA = wbkA.Worksheets("OSM37")
Set wbkB = Workbooks.Open(Filename:="H:\Chelsea QE\CD6\Evan West\New folder\Flat Rock and Roush VIN Tracker U625 - U611 Lower control arm welds.xlsx")
Set SheetB = wbkB.Worksheets("Master VIN")
'This is the range in SheetA
RangeToCheckA = "B2:B239"
'This is the range in SheetB
RangeToCheckB = "B4:B1339"
'Value 2 is faster as it doesn't copy formatting
arrySheetA() = SheetA.Range(RangeToCheckA).Value2
arrySheetB() = SheetB.Range(RangeToCheckB).Value2
Set SheetC = wbkB.Worksheets("Sheet C")
arryOut() = FastLookUp(arrySheetA, arrySheetB, 1, 1, 1)
SheetC.Range("A1").Resize(UBound(arryOut, 1), _
UBound(arryOut, 2)).Value = arryOut
End Sub
FastLookUp Function:
Private Function FastLookUp(ByRef arryLookUpVals As Variant, ByRef arryLookUpTable As Variant, _
ByVal lngLookUpValCol As Long, ByVal lngSearchCol As Long, _
ByVal lngReturnCol As Long, _
Optional ByVal boolBinaryCompare As Boolean = True) As Variant
Dim i As Long
Dim dictLooUpTblData As Object
Dim varKey As Variant
Dim arryOut() As Variant
Set dictLooUpTblData = CreateObject("Scripting.Dictionary")
If boolBinaryCompare Then
dictLooUpTblData.CompareMode = vbBinaryCompare
Else
dictLooUpTblData.CompareMode = vbTextCompare
End If
'add lookup table's lookup column to
'dictionary
For i = LBound(arryLookUpTable, 1) To UBound(arryLookUpTable, 1)
varKey = Trim(arryLookUpTable(i, lngSearchCol))
If Not dictLooUpTblData.Exists(varKey) Then
'this is called a silent add with is faster
'than the standard dictionary.Add Key,Item
'method
dictLooUpTblData(varKey) = arryLookUpTable(i, lngReturnCol)
End If
varKey = Empty
Next i
i = 0: varKey = Empty
ReDim arryOut(1 To UBound(arryLookUpVals, 1), 1 To 1)
For i = LBound(arryLookUpVals, 1) To UBound(arryLookUpVals, 1)
varKey = Trim(arryLookUpVals(i, lngLookUpValCol))
'if the lookup value exists in the dictionary
'at this index of the array, then return
'its correspoding item
If dictLooUpTblData.Exists(varKey) Then
arryOut(i, 1) = dictLooUpTblData.Item(varKey)
End If
varKey = Empty
Next i
FastLookUp = arryOut
End Function
FastLookup functions exactly like a VLOOKUP, but is a bit more flexible, because the the lookup column does not have to be the first one in the range you are looking up, as you are allowed to specify which column by providing a value for lngLookUpValCol parameter.
Concerning that you have 3 worksheets in 1 workbook - Worksheets(1) and Worksheets(2) are the one, in which the values in Range("A1:A7") and Range("A1:A3") are compared:
Sub TestMe()
Dim arrA As Variant
Dim arrB As Variant
With Application
arrA = .Transpose(Worksheets(1).Range("A1:A7"))
arrB = .Transpose(Worksheets(2).Range("A1:A3"))
End With
Dim a As Variant
Dim b As Variant
For Each a In arrA
For Each b In arrB
If a = b Then
Worksheets(3).Cells(1 + LastRow(Worksheets(3).Name), 1) = b
End If
Next
Next
End Sub
Function LastRow(wsName As String, Optional columnToCheck As Long = 1) As Long
Dim ws As Worksheet
Set ws = Worksheets(wsName)
LastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row
End Function
If you are planning to use the code above, it is a good idea to make sure that the values in Worksheets(1) are all unique, otherwise the code would repeat them N times. Or add a dictionary, to exclude repeated values.
I need to search similar string which exist under same column from a input excel file and group them together and perform some calculation.
Example say : I have input file named : Predictions
FUND_NAME CLASS_NAME FUND_CODE CASHFLOW_IN_FUND_CURRENCY
AA BB SSIS 19200
VV DD SPIS 16200
QQ NN BNIS 15830
CC DJ SSIS -6300
I want a code in VBA which should combine Similar Fund_Codes together and perform some logical calculations on CASHFLOW_IN_FUND_CURRENCY .
Say When 1st nd 4th row has same fund code (SSIS) then I need to ABS(sum(19200-6300))
I know the logic for calculations ,but couldn't find the logic to group the fund_code within same worksheet and same column.
I had tried the Rachels method fuzzy logic in stack overlow but it didn't work ,
I also tried the below code and it did not work .
Dim ws As Worksheet
Dim lRow As Long, i As Long
Set ws = ThisWorkbook.Sheets("TRANS")
Dim rngFundCode As Range
lRow = Sheet1.Range("C" & Rows.Count).End(xlUp).Row
Set rngFundCode = Range("C:C")
For i = 2 To lRow
Cells(i, 3) = Application.WorksheetFunction.VLookup(Cells(i, 1), rngFundCode, 2, False)
Next i
Could anyone ,let me know how to group the similr string within same column and prform some logic calculation on the other column
Dim ws As Worksheet
Dim lRow As Long, i As Long
Set ws = ThisWorkbook.Sheets("TRANS")
Dim rngFundCode As Range
lRow = Sheet1.Range("C" & Rows.Count).End(xlUp).Row
Set rngFundCode = Range("C:C")
For i = 2 To lRow
Cells(i, 3) = Application.WorksheetFunction.VLookup(Cells(i, 1), rngFundCode, 2, False)
Next i
I want a code in VBA which should combine Similar Fund_Codes together and perform some logical calculations on CASHFLOW_IN_FUND_CURRENCY .
Say When 1st nd 4th row has same fund code (SSIS) then I need to ABS(sum(19200-6300))
I created a class and got the values as a collection from the input file and got this resolved.
Function CalculateReport() As Boolean
Dim bOutput As Boolean: bOutput = False
Dim colPrediction As Collection
Dim objPred As clsPrediction
Dim shtPred As Worksheet
Dim colFunds As New Collection
On Error GoTo ErrorAccessingFile
Set shtPred = g_colInputFiles("txtPredictions").GetSheets(1).GetSheet
On Error GoTo 0
'Get Data from Input Files
Set colPrediction = GetPredictionData(shtPred)
Dim col As Collection
'Split the data by FundCode
For Each objPred In colPrediction
If ItemIsInCollection(colFunds, objPred.Fund_Code) Then
Set col = colFunds(objPred.Fund_Code)
col.Add objPred, objPred.getKey
Else
Set col = New Collection
col.Add objPred, objPred.getKey
colFunds.Add col, objPred.Fund_Code
End If
Next objPred
For Each col In colFunds
If col.Count > 1 Then
'Apply Formula
End If
Next col
I need the row/column combinations marked with an 'X' in my table to be available as three columns in another sheet.
The first column will consist of the cell address,
the second column will have the Row Name, and
the third column will have the Column name of the marked cells.
VLookUp and Index/Match are not helping.
Expected result:
You might get away with something as lazy as, you would change the sheets and the target range srcSht.Range("A1:C5") as appropriate:
Option Explicit
Sub test()
Dim wb As Workbook
Dim srcSht As Worksheet
Dim destSht As Worksheet
Set wb = ThisWorkbook
Set srcSht = wb.Sheets("Sheet1")
Set destSht = wb.Sheets("Sheet2")
Dim targetRange As Range
Set targetRange = srcSht.Range("A1:C5")
Dim loopArray()
loopArray = targetRange.Value2
Dim currRow As Long
Dim currCol As Long
Dim counter As Long
For currRow = LBound(loopArray, 1) To UBound(loopArray, 1)
For currCol = LBound(loopArray, 2) To UBound(loopArray, 2)
If LCase$(loopArray(currRow, currCol) )= "x" Then
counter = counter + 1
destSht.Cells(counter, 1) = targetRange.Cells(currRow, currCol).Address
destSht.Cells(counter, 2) = "Column " & targetRange.Cells(currRow, currCol).Column
destSht.Cells(counter, 3) = "Row " & targetRange.Cells(currRow, currCol).Row
End If
Next currCol
Next currRow
End Sub
This array formula seems to be working for me
=IFERROR(ADDRESS(SMALL(IF($A$1:$C$6="X",ROW($A$1:$C$6)*100+COLUMN($A$1:$C$6)),ROW())/100,MOD(SMALL(IF($A$1:$C$6="X",ROW($A$1:$C$6)*100+COLUMN($A$1:$C$6)),ROW()),100)),"")
but I think could be done more tidily with AGGREGATE.
Also there's no particular reason for multiplying by 100, multiplying by the exact number of columns in the array plus 1 would be better.
Here it is with AGGREGATE
=IFERROR(ADDRESS(AGGREGATE(15,6,(ROW($A$1:$C$6)*100+COLUMN($A$1:$C$6))/($A$1:$C$6="X"),ROW())/100,MOD(AGGREGATE(15,6,(ROW($A$1:$C$6)*100+COLUMN($A$1:$C$6))/($A$1:$C$6="X"),ROW()),100)),"")
EDIT
Here is a more general solution for a 2d range of any size anywhere on the sheet.
For the row:
=IFERROR(INDEX($A$2:$A$7,AGGREGATE(15,6,((ROW($B$2:$D$7)-ROW($B$2))*COLUMNS($B$2:$D$7)+COLUMN($B$2:$D$7)-COLUMN($B$2))/($B$2:$D$7="X"),ROW())/COLUMNS($B$2:$D$7)+1),"")
For the column:
=IFERROR(INDEX($B$1:$D$1,MOD(AGGREGATE(15,6,((ROW($B$2:$D$7)-ROW($B$2))*COLUMNS($B$2:$D$7)+COLUMN($B$2:$D$7)-COLUMN($B$2))/($B$2:$D$7="X"),ROW()),COLUMNS($B$2:$D$7))+1),"")
For the cell address:
=IFERROR(ADDRESS(AGGREGATE(15,6,((ROW($B$2:$D$7)-ROW($B$2))*COLUMNS($B$2:$D$7)+COLUMN($B$2:$D$7)-COLUMN($B$2))/($B$2:$D$7="X"),ROW())/COLUMNS($B$2:$D$7)+ROW($B$2),
MOD(AGGREGATE(15,6,((ROW($B$2:$D$7)-ROW($B$2))*COLUMNS($B$2:$D$7)+COLUMN($B$2:$D$7)-COLUMN($B$2))/($B$2:$D$7="X"),ROW()),COLUMNS($B$2:$D$7))+COLUMN($B$2)),"")
Here's a similar way to get a similar result:
Sub listCells()
Dim rIn As Range, c As Range, rOut As Range
Set rIn = Sheets("Sheet1").Range("B2:D7") 'input range
Set rOut = Sheets("Sheet1").Range("F1") 'first cell for output
For Each c In rIn
If c <> "" Then 'not blank so populate output
Range(rOut, rOut.Offset(, 2)) = Array(c.Address, c.Column - 1, c.Row - 1)
Set rOut = rOut.Offset(1, 0) 'next row
End If
Next c
End Sub