Loop to Fill Down to Next Specified Value and Repeat - excel

I have qualitative values in column A and quantitative values in column B associated with them.
I want to look for a specific value in column A, starting with A1. Once the value is found, I want to fill the value associated with it in column B down to the last row before the next value is found in column A. I want to repeat this until no more data is available in column A.
I have tried a number of formulas, but I think a VBA loop might be needed since I have nearly 25,000 rows.
Below is a visualization of what I am trying to do, looking for "W" and filling down. I greatly appreciate any thoughts or ideas!

Fill Down Column With Matched Value
Option Explicit
Sub UpdateColumn()
' Define constants.
Const FirstRowAddress As String = "A1:B1" ' at least two columns!
Const sStringColumn As Long = 1
Const dNumberColumn As Long = 2
Const CriteriaString As String = "W"
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = ActiveSheet 'improve!
' Declare variables referenced or calculated
' in the following With statement.
Dim rg As Range
Dim rCount As Long
' Reference the range ('rg') and write its number of rows
' to a variable ('rCount').
With ws.Range(FirstRowAddress)
Dim lCell As Range: Set lCell = .Resize(ws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If lCell Is Nothing Then
MsgBox "No data in range.", vbCritical
Exit Sub
End If
rCount = lCell.Row - .Row + 1
Set rg = .Resize(rCount)
End With
' Write the values from the range to a 2D one-based array,
' the source array ('sData').
Dim sData() As Variant: sData = rg.Value
' Define the 2D one-based one-column destination array ('dData').
Dim dData() As Double: ReDim dData(1 To rCount, 1 To 1)
' Declare variables to be used in the following For...Next loop.
Dim sString As String
Dim dValue As Variant
Dim dNumber As Double
Dim r As Long
' Write the required values from the source array to the destination array.
For r = 1 To rCount
sString = CStr(sData(r, sStringColumn))
If StrComp(sString, CriteriaString, vbTextCompare) = 0 Then ' is equal
dValue = sData(r, dNumberColumn)
If VarType(dValue) = vbDouble Then ' is a number
dNumber = CDbl(dValue)
Else ' is not a number
dNumber = 0
End If
'Else ' is not equal; do nothing (use current number)
End If
dData(r, 1) = dNumber
Next r
' Reference the destination range ('drg').
Dim drg As Range: Set drg = rg.Columns(dNumberColumn)
' Overwrite the destination range values with the required values
' from the destination array.
drg.Value = dData
' Inform.
MsgBox "Column updated.", vbInformation
End Sub

If I've understood what you need this could fit
Sub test()
Dim LR As Long, Rng As Range, StartRow As Long, EndRow As Long, StartVal, c
LR = Cells(Rows.Count, 1).End(xlUp).Row
Set Rng = Range(Cells(1, 1), Cells(LR, 1))
Set c = Columns(1).Find("W", after:=Cells(LR, 1), LookIn:=xlValues, LookAt:=xlWhole)
If Not c Is Nothing Then
firstAddress = c.Address
Do
StartRow = c.Row
StartVal = c.Offset(0, 1).Value
Set c = Rng.FindNext(c)
EndRow = IIf(c.Row > StartRow, c.Row, LR)
Range(Cells(StartRow + 1, 2), Cells(EndRow - 1, 2)) = StartVal
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End Sub

Related

Populate cells based on all values in array, append values if they do not exist in the cell range

I have an array of values result that I got from a REST API call. result = [1,2,3,4,5]
In the beginning
I want to input each value in the array result to populate cells from A1 to A5 (the range is dynamic, based on the number of values in the array, so might not be A5 all the time).
So, if the range (A1-A100) is empty, we populate the cells normally.
As the result array grows
Since the result will increase as we run the Macro again, for example, 15 minutes later the result becomes [1,2,3,4,5,6,7,8]
So, if the range (A1-A5) is not empty, we append the array's additional items at the back of the cell range, if they do not appear in the range (meaning they are additional ones)
I am thinking maybe I should do something like this if the range (A1-A5) is empty:
Given result = [1,2,3,4,5]
'the beginning part'
i = 1
Set rng = Range(“A1:A5”)
If WorksheetFunction.CountA(Range("A1:A5")) = 0 Then
For Each cel In rng:
result(i) = cel.Value
i = i + 1
Next cel
However, I think there's a major problem in the code & some missing part when array grows, because
The number of items in array is uncertain, so shouldn't hardcode value, should make it dynamic
When result array grows, I am not sure how to append only the additional items to the back of the cells list, this consist of (1) filtering out items in array that did not appear in the range (2) appending the items in correct positions
Any help would be greatly appreciated, thanks in advance.
Append Unique Values
Usage
Sub AppendUniqueTest()
Dim Arr() As Variant: Arr = Array(1, 2, 3, 4, 5)
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
AppendUnique Arr, ws, "A1"
End Sub
The Method
Sub AppendUnique( _
Arr() As Variant, _
ByVal ws As Worksheet, _
ByVal FirstCellAddress As String, _
Optional ByVal OverWrite As Boolean = False)
' Write the data from the source range to the source array ('sData').
' Reference the first destination cell ('fCell').
If ws.AutoFilterMode Then ws.AutoFilterMode = False
Dim fCell As Range: Set fCell = ws.Range(FirstCellAddress)
Dim sData() As Variant, srCount As Long
With fCell
Dim lCell As Range: Set lCell = .Resize(ws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If Not lCell Is Nothing Then
srCount = lCell.Row - .Row + 1
If srCount = 1 Then
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = .Value
Else
sData = .Resize(srCount).Value
End If
If Not OverWrite Then Set fCell = lCell.Offset(1)
End If
End With
' Write the unique data from the source array to a dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim sr As Long
For sr = 1 To srCount: dict(CStr(sData(sr, 1))) = Empty: Next sr
Erase sData
' Define the destination array ('dData').
Dim lb As Long: lb = LBound(Arr)
Dim ub As Long: ub = UBound(Arr)
Dim dData() As Variant: ReDim dData(1 To ub - lb + 1, 1 To 1)
' Check the values from the given array ('Arr') against the values
' in the dictionary and write the non-matches to the destination array.
Dim dr As Long, c As Long, cString As String
For c = lb To ub
cString = CStr(Arr(c))
If Len(cString) > 0 Then ' is not blank
If Not dict.Exists(cString) Then ' is not in the dictionary
dict(cString) = Empty ' prevent dupes from the given array
dr = dr + 1
dData(dr, 1) = cString
End If
End If
Next c
If dr = 0 Then
MsgBox "No new values found.", vbExclamation
Exit Sub
End If
' Write the values from the destination array to the destination range.
fCell.Resize(dr).Value = dData
If OverWrite Then ' clear below
fCell.Resize(ws.Rows.Count - fCell.Row - dr + 1).Offset(dr).Clear
End If
' Inform.
MsgBox "Data appended.", vbInformation
End Sub

Find and paste values from one sheet to another in selected columns

I am trying to paste values from one sheet into another, both sheets have one unique column B "Bill ID".
I enter values in column p, q and w of sheet "reconciliation".
When I run the code it should paste these values in column p, q, w of bills sheet against same Bill ID, Bill ID in both sheets is in column 2.
One more thing, from reconciliation sheet for Bill ID, it should search only from b21 to last non empty row.
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsDisp As Worksheet: Set wsDisp = wb.Worksheets("Reconciliation")
Dim a As String
Dim b As String
Dim c As String
Dim e As Long
Dim F As String
Application.ScreenUpdating = False
a = wsDisp.Cells(19, 16).Value
b = wsDisp.Cells(19, 17).Value
c = wsDisp.Cells(19, 23).Value
e = MsgBox("Do You Wish to Save Recovery ? " & vbNewLine & "GIDC PAID = " & a & vbNewLine & "GST PAID = " & b & vbNewLine & " LPS PAID = " & c, vbYesNo)
If e = vbNo Then Exit Sub
For i = 21 To 400
Sheets("Bills").Cells(Cells(i, 2), 16) = Sheets("Reconciliation").Cells(i, 16)
Sheets("Bills").Cells(Cells(i, 2), 17) = Sheets("Reconciliation").Cells(i, 17)
Sheets("Bills").Cells(Cells(i, 2), 23) = Sheets("Reconciliation").Cells(i, 23)
Next
Application.ScreenUpdating = True
Reconciliation Sheet
Bills
Update Cells in Matching Rows
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Updates the 'Bills' worksheet.
' Calls: 'RefColumn','GetRange'.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub UpdateBills()
' Source
Const sName As String = "Reconciliation"
Const sfRow As Long = 21
Const suCol As String = "B"
Const sColsList As String = "P,Q,W"
' Destination
Const dName As String = "Bills"
Const dfRow As Long = 2
Const duCol As String = "B"
Const dColsList As String = "P,Q,W"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
' Create references to the read-columns ('surg' and 'durg')
' and write only destination column to an array ('duData').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim surg As Range: Set surg = RefColumn(sws.Cells(sfRow, suCol))
If surg Is Nothing Then Exit Sub ' no data
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim durg As Range: Set durg = RefColumn(dws.Cells(dfRow, duCol))
If durg Is Nothing Then Exit Sub ' no data
' This is not done for the source because 'Application.Match'
' is multiple times faster on a range.
Dim duData As Variant: duData = GetRange(durg)
' Write values from the write-columns to jagged arrays.
' Split the lists (comma-separated strings) to arrays.
Dim sCols() As String: sCols = Split(sColsList, ",")
Dim dCols() As String: dCols = Split(dColsList, ",")
Dim cUpper As Long: cUpper = UBound(sCols)
' Define the jagged arrays.
Dim sData As Variant: ReDim sData(0 To cUpper)
Dim dData As Variant: ReDim dData(0 To cUpper)
' Define destination empty array ('drData').
Dim drCount As Long: drCount = UBound(duData, 1)
Dim drData As Variant: ReDim drData(1 To drCount, 1 To 1)
Dim c As Long
' Write values from the source write-columns to the source jagged array,
' and destination empty arrays to destination jagged array.
For c = 0 To cUpper
sData(c) = GetRange(surg.EntireRow.Columns(sCols(c)))
dData(c) = drData
Next c
Erase drData
' Write matches from source (jagged) array ('sData')
' to destination (jagged) array ('dData').
Dim dr As Long
Dim sIndex As Variant
For dr = 1 To drCount
sIndex = Application.Match(duData(dr, 1), surg, 0)
If IsNumeric(sIndex) Then
For c = 0 To cUpper
dData(c)(dr, 1) = sData(c)(sIndex, 1)
Next c
End If
Next dr
Erase duData
Erase sData
' Write values from destination array tp destination ranges.
For c = 0 To cUpper
durg.EntireRow.Columns(dCols(c)).Value = dData(c)
Next c
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the one-column range from the first cell
' of a range ('FirstCell') to the bottom-most non-empty cell
' of the first cell's worksheet column.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefColumn( _
ByVal FirstCell As Range) _
As Range
If FirstCell Is Nothing Then Exit Function
With FirstCell.Cells(1)
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Function
Set RefColumn = .Resize(lCell.Row - .Row + 1)
End With
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the values of a range ('rg') in a 2D one-based array.
' Remarks: If ˙rg` refers to a multi-range, only its first area
' is considered.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetRange( _
ByVal rg As Range) _
As Variant
If rg Is Nothing Then Exit Function
If rg.Rows.Count + rg.Columns.Count = 2 Then ' one cell
Dim Data As Variant: ReDim Data(1 To 1, 1 To 1): Data(1, 1) = rg.Value
GetRange = Data
Else ' multiple cells
GetRange = rg.Value
End If
End Function

How to count the number of unique strings separated by a space in each cell?

I have strings of numbers in one column, each cell contains from 1 to n sequences separated by a space e.g.
1001
2034 2034 2034
3456 3456 3456
is there a way to count how many unique sequences exist in each cell and place this number in the adjacent cell?
So e.g.
Column 1 Column 2
1001 1
2034 2034 2034 1
3456 3456 3456 1
3455 3455 5674 2
1234 3456 3456 4568 6754 4
So, I have managed to get to this point but how do I go about the range and the loop to basically print the result to each cell (to the right) of the analysed range?
Sub CountStuff()
Dim c As Collection
Set c = New Collection
ary = Split(ActiveCell.Value, " ")
On Error Resume Next
For Each a In ary
c.Add a, CStr(a)
Next a
On Error GoTo 0
Debug.Print c.Count
End Sub
Following from my comment above:
Sub CountStuff()
Dim col As Collection, c As Range, arr, v, rng As Range
Set rng = ActiveSheet.Range("A2:A100") 'for example
For Each c In rng.Cells
If Len(c.Value) > 0 Then
arr = Split(c.Value, " ")
Set col = New Collection
For Each v In arr
If Len(v) > 0 Then
On Error Resume Next 'ignore error on duplicate key
col.Add v, CStr(v)
On Error GoTo 0
End If
Next v
c.Offset(0, 1).Value = col.Count 'put count one cell over
End If
Next c
End Sub
Count Unique Substrings (UDF)
The Function
Option Explicit
Function CountUniqueSubStrings( _
ByVal SplitString As String, _
Optional ByVal Delimiter As String = " ") _
As Long
Dim SubStrings() As String: SubStrings = Split(SplitString, Delimiter)
Dim ssCount As Long: ssCount = UBound(SubStrings)
Dim usCount As Long
If ssCount < 1 Then
usCount = ssCount + 1
Else
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim cString As String
Dim n As Long
For n = 0 To ssCount
cString = SubStrings(n)
If Len(cString) > 0 Then
dict(SubStrings(n)) = Empty
End If
Next n
usCount = dict.Count
End If
CountUniqueSubStrings = usCount
End Function
Excel Example
=CountUniqueSubStrings(A1)
VBA Example
Sub CountUniqueSubStringsTEST()
' Define constants.
Const sFirst As String = "A2"
Const dFirst As String = "B2"
Const Delimiter As String = " "
' Create a reference to the worksheet.
Dim ws As Worksheet: Set ws = ActiveSheet
' Maybe better examples:
'Set ws = Sheet1
'Set ws = ThisWorkbook.Worksheets("Sheet1")
' Create a reference to the Source Column Range.
Dim srg As Range
Dim rCount As Long
With ws.Range(sFirst)
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If fCell Is Nothing Then Exit Sub
rCount = lCell.Row - .Row + 1
Set srg = .Resize(rCount)
Debug.Print srg.Address
End With
' Write values from the Source Column Range to the Data Array.
Dim Data As Variant
If rCount = 1 Then ' one cell only
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = srg.Value
Else
Data = srg.Value
End If
' Replace the values in the Data Array with the 'unique counts'.
Dim r As Long
For r = 1 To rCount
Data(r, 1) = CountUniqueSubStrings(Data(r, 1), Delimiter)
Next r
' Create a reference to the Destination Column Range.
Dim drg As Range: Set drg = ws.Range(dFirst).Resize(rCount)
' Write the 'unique counts' from the Data Array
' to the Destination Column Range.
drg.Value = Data
' Clear the contents below the Destination Column Range.
With drg.Cells(1)
.Resize(.Worksheet.Rows.Count - .Row - rCount + 1) _
.Offset(rCount).ClearContents
End With
End Sub

Change the value of each cell that meets criteria in a column

I am trying to change the value of each cell in column 7 that meets criteria. So far I managed to change the value with one criteria but I would like to add up to 14 criteria. Thanks for your help
Sub ChangeValue()
Dim i As Integer
Dim WK As Worksheet
Dim rg1 As range
Dim rg2 As range
Set WK = Sheet4
Set rg1 = range("AB2")
Set rg2 = range("AB3")
For i = Cells(Rows.Count, 7).End(xlUp).Row To 1 Step -1
If Cells(i, 7).Value = rg1 Then
Cells(i, 7).Value = rg2.Value
End If
Next i
End Sub
I would like to have more conditions something like if = AB3 change to AB4 if= AB4 Change to AB5 and so on...
To create a variable list of value/replace value pairs I would suggest using a dictionary:
Option Explicit
Sub ChangeValue()
Dim d
Set d = CreateObject("Scripting.Dictionary")
Dim r_test_value As Range
Dim r_anchor As Range
Set r_anchor = Range("AB2")
'need at least 2 values
If Not IsEmpty(r_anchor) And Not IsEmpty(r_anchor.Offset(1, 0)) Then
Set r_test_value = Range(r_anchor, _
Cells(Rows.Count, r_anchor.Column).End(xlUp).Offset(-1, 0))
Debug.Print r_test_value.Address
Dim i As Long
i = 0
Dim r As Range
For Each r In r_test_value
d.Add r.Value, r.Offset(i+1, 0).Value
i = i + 1
Next r
For i = Cells(Rows.Count, 7).End(xlUp).Row To 1 Step -1
If d.exists(Cells(i, 7).Value) Then
Cells(i, 7).Value = d.Item(Cells(i, 7).Value)
End If
Next i
End If
End Sub
Search and Replace Cell Values
EDIT
This is a more appropriate solution.
Adjust the starting rows i.e. For i = ? and For k = ?
Second Answer
Sub replaceValues()
' Determine Source Last Row.
Dim sLastRow As Long
sLastRow = Sheet4.Cells(Sheet4.Rows.Count, "AB").End(xlUp).Row
' Determine Destination Last Row.
Dim dLastRow As Long
dLastRow = Sheet4.Cells(Sheet4.Rows.Count, "G").End(xlUp).Row
Dim i As Long ' Destination Range Rows Counter
Dim k As Long ' Source Rows Counter
' Loop through rows of Destination Range.
For i = 2 To dLastRow
' Loop through rows of Source Range.
For k = 1 To sLastRow - 1
' When a value is found...
If Sheet4.Cells(i, "G").Value = Sheet4.Cells(k, "AB").Value Then
' ... replace it with the value below.
Sheet4.Cells(i, "G").Value = Sheet4.Cells(k + 1, "AB").Value
Exit For ' Value has been found and replaced. Stop searching.
' Otherwise you'll end up with the last replace value.
End If
Next k
Next i
' Inform.
MsgBox "Values replaced.", vbInformation, "Success"
End Sub
The First Answer (misunderstood)
The first solution is for using worksheet code names. It can be used for two worksheets. It is one in your case (Sheet4).
The second solution shows how to use it in two worksheets using worksheet names.
The code will loop through a column range of values and replace each value found in a row range of 'search values' with an associated 'replace value' in another same sized row range (in this case the ranges are adjacent, one below the other).
The Code
Option Explicit
Sub replaceValuesWorksheetCodeNames()
' Source
' Make sure the following two are of the same size.
Const srcAddress As String = "AB2:AO2"
Const rplAddress As String = "AB3:AO3"
' Destination
Const dFirstCell As String = "G2"
' Write Source Row Ranges to Source Arrays (Search and Replace).
With Sheet4
Dim srcData As Variant: srcData = .Range(srcAddress).Value
Dim rplData As Variant: rplData = .Range(rplAddress).Value
End With
' Define Destination Column Range.
Dim rg As Range
Dim RowOffset As Long
With Sheet4.Range(dFirstCell)
RowOffset = .Row - 1
Set rg = .Resize(.Worksheet.Rows.Count - RowOffset) _
.Find("*", , xlFormulas, , , xlPrevious)
If rg Is Nothing Then Exit Sub
Set rg = .Resize(rg.Row - RowOffset)
End With
' Write values from Destination Column Range to Data Array.
Dim rCount As Long: rCount = rg.Rows.Count
Dim Data As Variant
If rCount > 1 Then
Data = rg.Value
Else
ReDim Data(1 To 1, 1 To 1): Data = rg.Value
End If
' Search and replace values in Data Array.
Dim cValue As Variant
Dim cIndex As Variant
Dim i As Long
For i = 1 To rCount
cValue = Data(i, 1)
If Not IsError(cValue) Then
If Len(cValue) > 0 Then
cIndex = Application.Match(cValue, srcData, 0)
If IsNumeric(cIndex) Then
' When the replace data is in a row range.
Data(i, 1) = rplData(1, cIndex)
' When the replace data is in a column range.
'Data(i, 1) = rplData(cIndex, 1)
End If
End If
End If
Next i
' Write possibly modified values from Data Array back
' to Destination Column Range.
rg.Value = Data
' Inform.
MsgBox "Values replaced.", vbInformation, "Success"
End Sub
Sub replaceValuesWorksheetNames()
' Source
Const sName As String = "Sheet1"
' Make sure the following two are of the same size.
Const srcAddress As String = "AB2:AO2"
Const rplAddress As String = "AB3:AO3"
' Destination
Const dName As String = "Sheet2"
Const dFirstCell As String = "G2"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
' Write Source Row Ranges to Source Arrays (Search and Replace).
With wb.Worksheets(sName)
Dim srcData As Variant: srcData = .Range(srcAddress).Value
Dim rplData As Variant: rplData = .Range(rplAddress).Value
End With
' Define Destination Column Range.
Dim rg As Range
Dim RowOffset As Long
With wb.Worksheets(dName).Range(dFirstCell)
RowOffset = .Row - 1
Set rg = .Resize(.Worksheet.Rows.Count - RowOffset) _
.Find("*", , xlFormulas, , , xlPrevious)
If rg Is Nothing Then Exit Sub
Set rg = .Resize(rg.Row - RowOffset)
End With
' Write values from Destination Column Range to Data Array.
Dim rCount As Long: rCount = rg.Rows.Count
Dim Data As Variant
If rCount > 1 Then
Data = rg.Value
Else
ReDim Data(1 To 1, 1 To 1): Data = rg.Value
End If
' Search and replace values in Data Array.
Dim cValue As Variant
Dim cIndex As Variant
Dim i As Long
For i = 1 To rCount
cValue = Data(i, 1)
If Not IsError(cValue) Then
If Len(cValue) > 0 Then
cIndex = Application.Match(cValue, srcData, 0)
If IsNumeric(cIndex) Then
' When the replace data is in a row range.
Data(i, 1) = rplData(1, cIndex)
' When the replace data is in a column range.
'Data(i, 1) = rplData(cIndex, 1)
End If
End If
End If
Next i
' Write possibly modified values from Data Array back
' to Destination Column Range.
rg.Value = Data
' Inform.
MsgBox "Values replaced.", vbInformation, "Success"
End Sub

Need to Paste entire row from Sheet 2 to Sheet 3 if Value found in Sheet 1 A Column

I have master Data in Sheet 2 (Column B) and search criteria in Sheet 1 (Column A), i want VBA to find all the data from Sheet 1 (Column A) in Sheet 2 (Column B) if found cut the entire row and past it into Sheet 3 next available row.
Sub remDup()
Dim LR As Long, LRSheet2 As Long, i As Long, a As Long
Dim vAllSheet2Values() As Variant
LRSheet2 = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
LR = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
a = 1
For i = 1 To LRSheet2 'Load all values in ColumnA of Sheet2 into an array
ReDim Preserve vAllSheet2Values(i)
vAllSheet2Values(i) = Worksheets("Sheet2").Cells(i, 2).Value
Next i
For i = LR To 1 Step -1
If IsInArray(Worksheets("Sheet1").Cells(i, 1).Value, vAllSheet2Values) Then
Worksheets("Sheet1").Rows(i).Copy Worksheets("Sheet3").Rows(a)
Worksheets("Sheet1").Rows(i).Delete
a = a + 1
End If
Next i
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
in above code data is getting deleted from sheet 1 :( and not sheet 2
Backup Matching Rows
In the current setup, the code will search for all values in column A of Sheet1 in column B of Sheet2. The cells of each found value will be combined into a Total Range whose entire rows will be copied to Sheet3 (in one go) and then removed (deleted) from Sheet1 (in another go).
The Code
Option Explicit
Sub remDup()
' Constants
Const sName As String = "Sheet1"
Const sFirst As String = "A1"
Const lName As String = "Sheet2"
Const lFirst As String = "B1"
Const dName As String = "Sheet3"
Const dFirst As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = refColumn(sws.Range(sFirst))
If srg Is Nothing Then Exit Sub
Dim sData As Variant: sData = getColumn(srg)
' Lookup
Dim lws As Worksheet: Set lws = wb.Worksheets(lName)
Dim lrg As Range: Set lrg = refColumn(lws.Range(lFirst))
If lrg Is Nothing Then Exit Sub
Dim lData As Variant: lData = getColumn(lrg)
' Match
Dim trg As Range
Dim i As Long
For i = 1 To UBound(sData)
If foundMatchInVector(sData(i, 1), lData) Then
Set trg = getCombinedRange(trg, srg.Cells(i))
End If
Next i
' Destination
If Not trg Is Nothing Then
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' This is a kind of a ridiculous use of "refColumn".
Dim drg As Range: Set drg = refColumn(dws.Range(dFirst))
If drg Is Nothing Then
Set drg = dws.Range(dFirst).EntireRow
Else
Set drg = drg.Cells(drg.Cells.Count).Offset(1).EntireRow
End If
trg.EntireRow.Copy drg
trg.EntireRow.Delete
End If
End Sub
' Assumptions: 'FirstCellRange' is a one-cell range e.g. 'Range("A1")'.
' Returns: Either the range from 'FirstCellRange' to the bottom-most
' non-empty cell in the column, or 'Nothing' if all cells
' below 'FirstCellRange' (incl.) are empty.
Function refColumn( _
ByVal FirstCellRange As Range) _
As Range
With FirstCellRange
Dim cel As Range
Set cel = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If Not cel Is Nothing Then
Set refColumn = .Resize(cel.Row - .Row + 1)
End If
End With
End Function
' Assumptions: 'rg' is a one-column range e.g. 'Range("A1")', 'Range("A1:A2")'.
' Returns: A 2D one-based one-column array.
Function getColumn( _
rg As Range) _
As Variant
If rg.Rows.Count > 1 Then
getColumn = rg.Value
Else
Dim OneElement As Variant: ReDim OneElement(1 To 1, 1 To 1)
OneElement(1, 1) = rg.Value
getColumn = OneElement
End If
End Function
' Assumptions: 'MatchValue' is a simple data type (not an object or an array).
' 'Vector' is a structure that 'Application.Match' can handle,
' e.g. a 1D array, a one-column or one-row range or 2D array.
' Returns: 'True' or 'False' (boolean).
' Remarks: Error values and blanks are ignored ('False').
Function foundMatchInVector( _
ByVal MatchValue As Variant, _
ByVal Vector As Variant) _
As Boolean
If Not IsError(MatchValue) Then
If Len(MatchValue) > 0 Then
foundMatchInVector _
= IsNumeric(Application.Match(MatchValue, Vector, 0))
End If
End If
End Function
' Assumptions: 'AddRange' is not 'Nothing' and it is in the same worksheet
' as 'BuiltRange'.
' Returns: A range (object).
Function getCombinedRange( _
ByVal BuiltRange As Range, _
ByVal AddRange As Range)
If BuiltRange Is Nothing Then
Set getCombinedRange = AddRange
Else
Set getCombinedRange = Union(BuiltRange, AddRange)
End If
End Function
If I'm understanding correctly this should do it. I put comments on the changed lines
Sub remDup()
Dim LR As Long, LRSheet2 As Long, i As Long, a As Long
Dim vAllSheet1Values() As Variant 'This should be referencing sheet 1 not 2
LRSheet2 = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
LR = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
a = 1
ReDim Preserve vAllSheet1Values(LR) 'No need for this to be in a loop
For i = 1 To LR 'Load all values in ColumnA of Sheet1 into an array
vAllSheet1Values(i) = Worksheets("Sheet1").Cells(i, 1).Value 'This should be sheet1
Next i
For i = LRSheet2 To 1 Step -1 'This and all sheet1 references after should be sheet 2
If IsInArray(Worksheets("Sheet2").Cells(i, 1).Value, vAllSheet1Values) Then
Worksheets("Sheet2").Rows(i).Copy Worksheets("Sheet3").Rows(a)
Worksheets("Sheet2").Rows(i).Delete
a = a + 1
End If
Next i
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
Please, try the next code:
Sub remDup()
Dim LR As Long, LRSheet2 As Long, arr, i As Long, rngCopy As Range, rngDel As Range
Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet, a As Long
Set sh1 = Worksheets("Sheet1")
Set sh2 = Worksheets("Sheet2")
Set sh3 = Worksheets("Sheet3")
LRSheet2 = sh2.cells(Rows.count, 2).End(xlUp).row
LR = sh1.cells(Rows.count, 1).End(xlUp).row
a = 1 'The Sheet3 row where the rows to be copied
arr = sh2.Range("B1:B" & LRSheet2).Value 'put the range in a 2D array
arr = Application.Transpose(Application.Index(arr, 0, 1)) 'obtain 1D array
For i = 1 To LR
If IsInArray(sh1.cells(i, 1).Value, arr) Then
If rngCopy Is Nothing Then
Set rngCopy = sh1.cells(i, 1) 'create a range to be copied/deleted
Else
Set rngCopy = Union(rngCopy, sh1.cells(i, 1))
End If
End If
Next i
rngCopy.EntireRow.Copy sh3.Range("A" & a) 'copy the range entirerow at once
rngCopy.EntireRow.Delete 'delete the range entirerow
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = UBound(Filter(arr, stringToBeFound)) > -1
End Function

Resources