I am using below code which is comparing three columns values and copy pasting the 4th column data into other column.
My code is working fine but it is slow to perform the processing and takes much time and sometimes Not Responding window appears.
Any help to fix the problem will be appreciated
Sub rowMatch()
Dim ws As Worksheet
Dim ws2 As Worksheet
Set ws = Worksheets("Sheet3")
Set ws2 = Worksheets("Sheet2")
Dim a As String, b As String, c As Date
For i = 3 To ws.Cells(ws.Rows.Count, 14).End(xlUp).Row
a = ws.Cells(i, 14).Value
b = ws.Cells(i, 15).Value
c = ws.Cells(i, 16).Value
For j = 3 To ws2.Cells(ws2.Rows.Count, 98).End(xlUp).Row
If ws2.Cells(j, 98).Value = a _
And ws2.Cells(j, 103).Value = b _
And ws2.Cells(j, 114).Value = c _
Then
ws2.Cells(j, 120).Value = ws.Cells(j, 18).Value
End If
Next j
Next i
End Sub
A 'Triple' Lookup
When in a loop a condition 1. is not met or 2. is met, use Exit For to stop looping (to exit the loop).
Option Explicit
Sub TripleLookup()
' Source
Const sName As String = "Sheet3" ' Worksheet Name
Const sfRow As Long = 3 ' First Row
Const slColsList As String = "N,O,P" ' Lookup Columns
Const slrCol As String = "N" ' Last Row Column
Const svCol As String = "R" ' Value Column
' Destination
Const dName As String = "Sheet2" ' Worksheet Name
Const dfRow As Long = 3 ' First Row
Const dlColsList As String = "CT,CY,DJ" ' Lookup Columns
Const dlrcol As String = "CT" ' Last Row Column
Const dvCol As String = "DP" ' Value Column
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, slrCol).End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data
Dim srCount As Long: srCount = slRow - sfRow + 1
Dim slrrg As Range: Set slrrg = sws.Cells(sfRow, slrCol).Resize(srCount)
Dim slCols() As String: slCols = Split(slColsList, ",")
Dim cUpper As Long: cUpper = UBound(slCols)
Dim sData As Variant: ReDim sData(0 To cUpper)
Dim srg As Range
Dim n As Long
For n = 0 To cUpper
Set srg = slrrg.EntireRow.Columns(slCols(n))
sData(n) = srg.Value
Next n
Set srg = slrrg.EntireRow.Columns(svCol)
Dim svData As Variant: svData = srg.Value
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dlrcol).End(xlUp).Row
If dlRow < dfRow Then Exit Sub ' no data
Dim drCount As Long: drCount = dlRow - dfRow + 1
Dim dlrrg As Range: Set dlrrg = dws.Cells(dfRow, dlrcol).Resize(drCount)
Dim dlCols() As String: dlCols = Split(dlColsList, ",")
Dim dData As Variant: ReDim dData(0 To cUpper)
Dim drg As Range
For n = 0 To cUpper
Set drg = dlrrg.EntireRow.Columns(dlCols(n))
dData(n) = drg.Value
Next n
Dim dvData As Variant: ReDim dvData(1 To drCount, 1 To 1)
' Loop
Dim tUpper As Long: tUpper = cUpper + 1
Dim sr As Long
Dim dr As Long
For dr = 1 To drCount
For sr = 1 To srCount
For n = 0 To cUpper
If StrComp(CStr(sData(n)(sr, 1)), CStr(dData(n)(dr, 1)), _
vbTextCompare) <> 0 Then ' ignoring case
Exit For ' 1. mismatch found, no need to loop anymore
End If
Next n
If n = tUpper Then ' no mismatch, all are equal
dvData(dr, 1) = svData(sr, 1)
Exit For ' 2. value written, no need to loop anymore
End If
Next sr
Next dr
' Result
Set drg = dlrrg.EntireRow.Columns(dvCol)
drg.Value = dvData
End Sub
Looking at the code you have two nested For loops, which depending on the size of the dataset you're working with, it will likely continue to be an issue on the time it takes to complete the task. The more rows you have, the longer it will take to complete the tasks.
One possible solution that you might want to consider looking into is using power query to blend/merge/append and clean data. Then use VBA to do what Power Query doesn't do very well.
I've spent many years avoiding looking at PQ as a solution to these problems and was a VBA guy all the way, but now when I come across these types of problems,I would look at PQ first over VBA.
Related
I am a PhD student and new to VBA.
I have been trying to automate sorting 1,8 million data points into a format suitable for data analysis. I am stuck. Would really appreciate anyone's help!
I need to automate the following:
Cutting a range of data in x sequential rows with identical Sequence numbers in column B.
And then paste it onto the right next to the previous range.
I found this code Excel VBA cut and paste rage repeatedly
Sub Cutrange()
Dim i As Long
Dim Lrow As Long
Lrow = Cells(Rows.Count, 1).End(xlUp).Row
Dim oRange As Range, dRange As Range
Set oRange = Range(Cells(1, 1), Cells(124, 14))
Set dRange = Cells(1, 1)
For i = 1 To Lrow
oRange.Offset(124 * i).Cut Destination:=dRange.Offset(, 14 * i)
Next i
End Sub
However, this code cuts and pastes a pre-determined range of cells (124x14). In my data, the number of rows (to be cut and pasted) needs to change based on how many rows have the same Sequence number.
Could anyone kindly help to change this code to fit my purpose or suggest alternative solutions?
Thank you,
Anna
HStack Groups of Data (VBA)
Option Explicit
Sub HStackGroups()
Const SRC_NAME As String = "Sheet1"
Const SRC_FIRST_CELL As String = "B2"
Const DST_NAME As String = "Sheet2"
Const DST_FIRST_CELL As String = "B2"
Const UNIQUE_COLUMN As Long = 1
Const COLUMN_GAP As Long = 1
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Sheets(SRC_NAME)
Dim srg As Range: Set srg = sws.Range(SRC_FIRST_CELL).CurrentRegion
Dim hData(): hData = srg.Rows(1).Value
Dim cCount As Long: cCount = srg.Columns.Count
Dim srCount As Long: srCount = srg.Rows.Count - 1 ' no headers
Dim sData(): sData = srg.Resize(srCount).Offset(1).Value
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim sr As Long, drCount As Long, srString As String
For sr = 1 To srCount
srString = CStr(sData(sr, UNIQUE_COLUMN))
If Not dict.Exists(srString) Then
Set dict(srString) = New Collection
End If
dict(srString).Add sr
If dict(srString).Count > drCount Then drCount = dict(srString).Count
Next sr
drCount = drCount + 1 ' 1 for headers
Dim dCount As Long: dCount = cCount + COLUMN_GAP
Dim dcCount As Long
dcCount = dict.Count * dCount - COLUMN_GAP
Dim dData(): ReDim dData(1 To drCount, 1 To dcCount)
Dim Coll, Item, sc As Long, d As Long, dr As Long, dc As Long
For Each Coll In dict.Items
dc = d * dCount
For sc = 1 To cCount
dData(1, dc + sc) = hData(1, sc)
Next sc
dr = 1
For Each Item In Coll
dr = dr + 1
For sc = 1 To cCount
dData(dr, dc + sc) = sData(Item, sc)
Next sc
Next Item
d = d + 1
Next Coll
Dim dws As Worksheet: Set dws = wb.Sheets(DST_NAME)
Dim dfCell As Range: Set dfCell = dws.Range(DST_FIRST_CELL)
Dim drg As Range: Set drg = dfCell.Resize(drCount, dcCount)
With dfCell
.Resize(dws.Rows.Count - .Row + 1, dws.Columns.Count - .Column + 1) _
.Clear
End With
drg.Value = dData
drg.EntireColumn.AutoFit
MsgBox "Groups hstacked.", vbInformation
End Sub
I use this VBA code which works very well. It searches in column A of an external Excel file for all the terms in column D, and replaces the matches, with the content of column B of the external file in the found row. So for instance:
if D5 matches A11 of the external file, then B11 from external file is written to D5.
I am now trying to modify it so that it still searches in column 4 for matches in column A of external file, but for any matches found, replaces the column E with column B of the external file. So:
If D5 matches A11, then B11 from external file is written to E5.
Well, I've tried many changes in the replace loop but it throws errors every time. I suppose I don't use the correct command!
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook, thisWb As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet
Dim i As Long, lRow As Long
'This is the workbook from where code runs
Set thisWb = ThisWorkbook
Set thisWs = thisWb.Sheets("Sheet1")
'External file
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
With NameListWS
'Detect end row in Col A of Data.xlsx
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'Loop though Column A
For i = 1 To lRow
'... and perform replace action
thisWs.Columns(4).Replace What:=.Range("A" & i).Value, _
Replacement:=.Range("B" & i).Value, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next i
End With
End Sub ```
Untested:
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet, n As Long
Dim i As Long, arrList, arrD, rngD As Range
Set thisWs = ThisWorkbook.Sheets("Sheet1") 'This is the workbook from where code runs
'get an array from the column to be searched
Set rngD = thisWs.Range("D1:D" & thisWs.Cells(Rows.Count, "D").End(xlUp).Row)
arrD = rngD.Value
'Open external file and get the terms and replacements as an array
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
With NameListWB.Worksheets("Sheet1")
arrList = .Range("A1:B" & .Cells(Rows.Count, "A").End(xlUp).Row).Value
End With
For n = 1 To UBound(arrD, 1) 'check each value from ColD
For i = 1 To UBound(arrList, 1) 'loop over the array of terms to search for
If arrD(n, 1) = arrList(i, 1) Then 'exact match ?
'If InStr(1, arrD(n, 1), arr(i, 1)) > 0 Then 'partial match ?
rngD.Cells(n).Offset(0, 1).Value = arrList(i, 2) 'populate value from ColB into ColE
Exit For 'got a match so stop searching
End If
Next i
Next n
End Sub
A VBA Lookup (Application.Match)
Adjust (play with) the values in the constants section.
Compact
Sub VBALookup()
' Source
Const sPath As String = "E:\Data.xlsx"
Const sName As String = "Sheet1"
Const slCol As String = "A" ' lookup
Const svCol As String = "B" ' value
Const sfRow As Long = 2
' Destination
Const dName As String = "Sheet1"
Const dlCol As String = "D" ' lookup
Const dvCol As String = "E" ' value
Const dfRow As Long = 2
Application.ScreenUpdating = False
' Source
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, slCol).End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data in lookup column range
Dim srCount As Long: srCount = slRow - sfRow + 1
Dim slrg As Range: Set slrg = sws.Cells(sfRow, slCol).Resize(srCount)
Dim svData As Variant
With slrg.EntireRow.Columns(svCol)
If srCount = 1 Then ' one cell
ReDim svData(1 To 1, 1 To 1): svData(1, 1) = .Value
Else ' multiple cells
svData = .Value
End If
End With
' Destination
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dlCol).End(xlUp).Row
If dlRow < dfRow Then Exit Sub ' no data in lookup column range
Dim drCount As Long: drCount = dlRow - dfRow + 1
Dim dlrg As Range: Set dlrg = dws.Cells(dfRow, dlCol).Resize(drCount)
Dim dData As Variant
If drCount = 1 Then ' one cell
ReDim dData(1 To 1, 1 To 1): dData(1, 1) = dlrg.Value
Else ' multiple cells
dData = dlrg.Value
End If
' Loop.
Dim srIndex As Variant
Dim dValue As Variant
Dim dr As Long
Dim MatchFound As Boolean
For dr = 1 To drCount
dValue = dData(dr, 1)
If Not IsError(dValue) Then
If Len(dValue) > 0 Then
srIndex = Application.Match(dValue, slrg, 0)
If IsNumeric(srIndex) Then MatchFound = True
End If
End If
If MatchFound Then
dData(dr, 1) = svData(srIndex, 1)
MatchFound = False
Else
dData(dr, 1) = Empty
End If
Next dr
' Close the source workbook.
swb.Close SaveChanges:=False
' Write result.
dlrg.EntireRow.Columns(dvCol).Value = dData
' Inform.
Application.ScreenUpdating = True
MsgBox "VBA lookup has finished.", vbInformation
End Sub
pls help, I need a excel vba code, which copies every second value of a row
and paste that into a column in another sheet
.
I tried it like this
Sub Test()
Worksheets("Sheet1").Activate
Dim x As Integer
For x = 5 To 196 Step 2
Worksheets("Tabelle1").Activate
Cells(x, 2).Value = Sheets("Sheets1").Range("E2:GN2")
Next x
End Sub
Sub test()
Dim WkSource As Worksheet
Dim WkDestiny As Worksheet
Dim i As Long
Dim j As Long
Dim LR As Long
Dim k As Long
Set WkSource = ThisWorkbook.Worksheets("Hoja1")
Set WkDestiny = ThisWorkbook.Worksheets("Hoja2")
With WkSource
LR = .Range("E" & .Rows.Count).End(xlUp).Row
k = 2 'starting row where you want to paste data in destiny sheet
For i = 2 To LR Step 1
For j = 5 To 12 Step 2 'j=5 to 12 because my data goes from column E to L (5 to 12)
WkDestiny.Range("D" & k).Value = .Cells(i, j).Value
k = k + 1
Next j
Next i
End With
Set WkSource = Nothing
Set WkDestiny = Nothing
End Sub
The code loop trough each row and each column (notice step 2 to skip columns)
Output I get:
you can start from something like this:
Option Explicit
Private Sub dataCp()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim ws2 As Worksheet: Set ws2 = wb.Sheets("Tabelle1")
Dim lrow As Long, lcol As Long, i As Long
Dim rng As Range, c As Range
lcol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
For i = 5 To lcol
lrow = (ws2.Cells(ws2.Rows.Count, "D").End(xlUp).Row) + 1
ws2.Range("D" & lrow).Value = ws.Cells(2, i).Value
i = i + 1
Next
End Sub
Transpose Data
It will transpose all rows of a range in a worksheet to consecutive columns on another worksheet.
Since scStep is 2, in this case, only every other cell in each source row will be copied.
Adjust (play with) the values in the constants section.
Option Explicit
Sub TransposeData()
' Source
Const sName As String = "Sheet1"
Const sFirstRowAddress As String = "E2:GN2"
Const scStep As Long = 2
' Destination
Const dName As String = "Tabelle1"
Const dFirstCellAddress As String = "D2"
' Both
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Write the values from the source range to the source array.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sData As Variant
Dim srCount As Long
With sws.Range(sFirstRowAddress)
' Populate data.
' With .Resize(20)
' .Formula = "=RANDBETWEEN(1,100)"
' .Value = .Value
' End With
Dim lCell As Range: Set lCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Sub ' no data in data range
srCount = lCell.Row - .Row + 1
sData = .Resize(srCount).Value
End With
' Define the destination array.
Dim scCount As Long: scCount = UBound(sData, 2)
Dim drCount As Long
drCount = Int(scCount / scStep) - CLng(scCount Mod scStep > 0)
Dim dData As Variant: ReDim dData(1 To drCount, 1 To srCount)
' Write the data from the source array to the destination array.
Dim r As Long, c As Long
For c = 1 To srCount
For r = 1 To drCount
dData(r, c) = sData(c, (r - 1) * scStep + 1)
Next r
Next c
' Write the values from the destination array to the destination range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
With dws.Range(dFirstCellAddress).Resize(, srCount) ' first row range
' Write data.
.Resize(drCount).Value = dData
' Clear below.
.Resize(dws.Rows.Count - .Row - drCount + 1).Offset(drCount).Clear
' Apply some formatting.
'.EntireColumn.AutoFit
End With
' Inform.
MsgBox "Data transposed.", vbInformation
End Sub
I have some code that works okay on a small data set, however, I'm looking for the most efficient way to handle this over in 100k+ rows.
The data is in two columns. In column B, wherever "Orange" is listed, I would like to copy/paste "Orange" into column A and replace "Citrus" for that row.
Here is my current code. I think it has some unnecessary bits in it now since I was trying to find a way to copy and paste all of the found cells at once.
SearchStr = "Orange"
Set SearchRng = Range("b2:b11)
With SearchRng
Set FoundCell = .Find(SearchStr, LookIn:=xlValues, LookAt:=xlPart)
If Not FoundCell Is Nothing Then
FirstAdd = FoundCell.Address
Do
If Not AllFoundCells Is Nothing Then
Set AllFoundCells = Union(AllFoundCells, FoundCell)
Else
Set AllFoundCells = FoundCell
End If
FoundCell.Copy Destination:=FoundCell.Offset(0, -1)
Set FoundCell = .FindNext(FoundCell)
Loop While FoundCell.Address <> FirstAdd
End If
End With
Replace If Match in Column
If a string (sString) is found in a column (sCol), then write another string (dString (in this case dString = sString)) to another column (dCol).
On my sample data of 1M rows (>200k of matches), it took less than 2s for the 'AutoFilter' solution and it took about 4s for the 'Array Loop' solution (3s for writing back to the range: drg.Value = dData).
Option Explicit
Sub UsingAutoFilter()
' Source
Const sCol As String = "B"
Const sString As String = "Orange"
' Destination
Const dCol As String = "A"
Const dString As String = "Orange"
' Both
Const hRow As Long = 1 ' Header Row
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
If ws.AutoFilterMode Then ws.AutoFilterMode = False
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, sCol).End(xlUp).Row
If lRow < hRow + 1 Then Exit Sub ' no data or just headers
Dim rCount As Long: rCount = lRow - hRow + 1
Dim srg As Range: Set srg = ws.Cells(hRow, sCol).Resize(rCount)
Dim sdrg As Range: Set sdrg = srg.Resize(srg.Rows.Count - 1).Offset(1)
srg.AutoFilter 1, sString
Dim sdvrg As Range
On Error Resume Next
Set sdvrg = sdrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
ws.AutoFilterMode = False
If sdvrg Is Nothing Then Exit Sub ' no match found
Dim ddvrg As Range
Set ddvrg = sdvrg.Offset(, ws.Columns(dCol).Column - srg.Column)
ddvrg.Value = dString
End Sub
Sub UsingArrayLoop()
' Source
Const sCol As String = "B"
Const sString As String = "Orange"
' Destination
Const dCol As String = "A"
Const dString As String = "Orange"
' Both
Const fRow As Long = 2 ' First Data Row
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, sCol).End(xlUp).Row
If lRow < fRow Then Exit Sub ' no data
Dim rCount As Long: rCount = lRow - fRow + 1
Dim srg As Range: Set srg = ws.Cells(fRow, sCol).Resize(rCount)
Dim drg As Range: Set drg = srg.EntireRow.Columns(dCol)
Dim sData As Variant
Dim dData As Variant
If rCount = 1 Then
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = srg.Value
ReDim dData(1 To 1, 1 To 1): dData(1, 1) = drg.Value
Else
sData = srg.Value
dData = drg.Value
End If
Dim r As Long
For r = 1 To rCount
If StrComp(CStr(sData(r, 1)), sString, vbTextCompare) = 0 Then
dData(r, 1) = dString
End If
Next r
Erase sData
drg.Value = dData
End Sub
Should be quicker than copy-paste:
Sub Tester()
Dim rw As Long, f As String
With ActiveSheet
rw = .Cells(.Rows.Count, "B").End(xlUp).Row
f = Replace("=IF(B2:B<rw>=""Orange"",B2:B<rw>,A2:A<rw>)", "<rw>", rw)
.Range("A2:A" & rw).value = .Evaluate(f) 'edited to remove `Application`
End With
End Sub
About 0.2sec for 100k rows
Evaluate() takes a worksheet function and evaluates it in the context of either the ActiveSheet (if you use the Application.Evaluate form) or a specific worksheet (if you use the WorkSheet.Evaluate form). It handles array formulas (no need to add the {}), and can return an array as the result (which here we just assign directly to the ColA range)
I have below code in which i want to create a loop for multiple values that are available in Sheet1.Range(A2:A100) code will pick one by one each value and match then paste result in Column B.
thisvalue = Sheet1.Range("A2:A100"). Can someone please help me to create the loop. Your help will be appreciated.
Sub Macro1()
Dim thisvalue As Double, sh As Worksheet, lastR As Long, arr, arrFin, i As Long
thisvalue = 3.61
Set sh = Worksheets("Sheet1")
lastR = sh.Range("J" & sh.rows.count).End(xlUp).row
arr = sh.Range("E7:J" & lastR).Value
ReDim arrFin(1 To UBound(arr), 1 To 1)
For i = 1 To UBound(arr)
If arr(i, 1) < thisvalue And arr(i, 2) > thisvalue Then arrFin(i, 1) = arr(i, 6)
Next i
sh.Range("B2").Resize(UBound(arrFin), 1).Value = arrFin
End Sub
Please, try the next code:
Sub Macro1__2()
Dim thisvalue As Double, sh As Worksheet, lastR As Long
Dim arrVal, arr, arrFin, i As Long, j As Long
Set sh = Worksheets("Sheet2")
arrVal = Worksheets("Sheet1").Range("Q2:Q100").Value
Worksheets("Sheet1").Range("R2:R200").ClearContents
lastR = sh.Range("J" & sh.Rows.Count).End(xlUp).Row
arr = sh.Range("E7:J" & lastR).Value
For j = 1 To UBound(arrVal)
thisvalue = arrVal(j, 1)
If CStr(thisvalue) <> "" Then 'excluding the cases of empty cells. I didn't know that they may exist
arrFin = Worksheets("Sheet1").Range("R2:R200").Value 'firstly input the existing range in the array
For i = 1 To UBound(arr)
If arr(i, 1) < thisvalue And arr(i, 2) > thisvalue Then arrFin(j, 1) = arr(i, 6)
Next i
Worksheets("Sheet1").Range("R2").Resize(UBound(arrFin), 1).Value = arrFin
End If
Next j
MsgBox "Ready..."
End Sub
Ranges and Arrays
Option Explicit
Sub Macro1()
' Source
Const sName As String = "Sheet1"
Const slrCol As String = "J"
Const sCols As String = "E:J"
Const sfRow As Long = 7
Const scColLess As Long = 1
Const scColGreater As Long = 2
Const srCol As Long = 6
Const sCriteria As Double = 3.61
' Destination
Const dName As String = "Sheet1"
Const dFirst As String = "B2"
' Create a reference to the Workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Create a reference to the Source Worksheet ('sws').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
' Create a reference to the Source Range ('srg').
If sws.Columns(sCols).Columns.Count < srCol Then Exit Sub ' too few columns
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, slrCol).End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data
Dim rCount As Long: rCount = slRow - sfRow + 1 ' for source and destination
Dim srg As Range
Set srg = sws.Rows(sfRow).Columns(sCols).Resize(rCount)
' Write the values from the Source Range
' to the Source Array ('sData').
Dim sData As Variant: sData = srg.Value
' Define the Destination Array ('dData').
Dim dData As Variant: ReDim dData(1 To rCount, 1 To 1)
' Write the appropriate values from the Source Array
' to the Destination Array.
Dim cValue As Variant
Dim r As Long
For r = 1 To rCount
cValue = sData(r, scColLess)
If IsNumeric(cValue) Then
If cValue < sCriteria Then
cValue = sData(r, scColGreater)
If IsNumeric(cValue) Then
If cValue > sCriteria Then
dData(r, 1) = sData(r, srCol)
End If
End If
End If
End If
Next r
' Create a reference to the Destination Worksheet ('dws').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' Create a reference to the Destination Range ('drg').
Dim dfCell As Range: Set dfCell = dws.Range(dFirst)
Dim drg As Range: Set drg = dfCell.Resize(rCount)
' Write the values from the Destination Array
' to the Destination Range ('drg').
drg.Value = dData
' Clear the Destination Clear Range ('dcrg'),
' the range below the Destination Range.
Dim dcrg As Range
Set dcrg = drg.Resize(dws.Rows.Count - drg.Row - rCount + 1).Offset(rCount)
dcrg.Clear ' or maybe rather 'dcrg.ClearContents'
' Format the Destination Range.
'drg.Font.Bold = True
'drg.EntireColumn.AutoFit
'drg.Interior.Color = 14348258
' Save the workbook.
'wb.Save
End Sub