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

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

Related

Loop to Fill Down to Next Specified Value and Repeat

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

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 copy formula result

How do I copy a formula result?
I select which rows to keep in the worksheet "UI", by marking the rows with the value 1 in column B.
I assigned the following macro to a command button, which copies the selected rows to the worksheet "Output":
Private Sub CommandButton1_Click()
Dim i As Integer
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("UI")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("Output")
For i = 2 To ws1.Range("B999").End(xlUp).Row
If ws1.Cells(i, 2) = "1" Then ws1.Rows(i).Copy ws2.Rows(ws2.Cells(ws2.Rows.Count, 2).End(xlUp).Row + 1)
Next i
End Sub
As the values in the rows are the results of formulas, the results pasted in "Output" come back as invalid cell references.
Is there a way of copy-pasting as text?
You should use "xlPasteValues" property to avoid invalid cell references when values in the rows are the results of formulas. You can try to modify your code as follows:
Private Sub CommandButton1_Click()
Dim i As Integer
Dim ws1 As Worksheet: Set ws1 = Sheets("UI")
Dim ws2 As Worksheet: Set ws2 = Sheets("Output")
For i = 2 To ws1.Range("B999").End(xlUp).Row
If ws1.Cells(i, 2) = "1" Then
ws1.Rows(i).Copy
ws2.Rows(ws2.Cells(ws2.Rows.Count, 2).End(xlUp).Row + 1).PasteSpecial Paste:=xlPasteValues
End If
Next i
End Sub
Copy Values of Rows with Criteria
It's not quite nifty, but efficient.
Adjust the values in the constants section.
The Code
Option Explicit
Private Sub CommandButton1_Click()
' Source
Const sName As String = "UI"
Const sFirstRow As Long = 2
Const Criteria As String = "1" ' 'Const Criteria as long = 1'?
' Destination
Const dName As String = "Output"
Const dCell As String = "A2"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
' Define Source Range (assuming 'UsedRange' starts in cell 'A1').
Dim rg As Range: Set rg = wb.Worksheets(sName).UsedRange
' Write values from Source Range to Data Array.
Dim Data As Variant: Data = rg.Value ' assuming 'rg' has at least two cells
Dim cCount As Long: cCount = UBound(Data, 2)
' Declare additional variables.
Dim cValue As Variant
Dim i As Long, j As Long, k As Long
' Loop and write matching values to the beginning of Data Array.
For i = sFirstRow To UBound(Data, 1)
cValue = Data(i, 2)
If Not IsError(cValue) Then
If cValue = Criteria Then
k = k + 1
For j = 1 To cCount
Data(k, j) = Data(i, j)
Next j
End If
End If
Next i
' Write matching values from Data Array to Destination Range.
If k > 0 Then
With wb.Worksheets(dName).Range(dCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
.Worksheet.Columns.Count - .Column + 1).ClearContents
.Resize(k, cCount).Value = Data
End With
MsgBox "Data transferred.", vbInformation, "Success"
Else
MsgBox "No matches found.", vbExclamation, "Fail?"
End If
End Sub

Macro That Detects More than 5 characters in Cell (zip code)

I have created a function that retrieves a Range based on column name. Here is my code:
Sub sep_Filter()
Dim zip_rng As String
With Sheet2
zip_rng = getColRangeFunction("postalcode")
If Len(Range(zip_rng)) > 5 Then
Range(zip_rng).Interior.Color = RGB(255, 0, 0)
Range(zip_rng).Select
Else
Range(zip_rng).Interior.Color = xlNone
End If
End With
End Sub
Sheet2 Input Column D
Sheet2 Output Column D
Sheet3 Output Column D
088762598
088762598
06610-5000
06610-5000
330161898
330161898
970152880
970152880
112202570
112202570
127420800
127420800
062262040
062262040
07631
07631
10029
10029
11803
11803
99336
99336
EDIT I misunderstood what you were asking, I updated my answer to be tied to your question.
Here's a basic approach that will do what you're asking. It skips row one.
Sub onlyfirst5()
Const pRange As String = "D1"
Dim ws As Worksheet
Set ws = ActiveSheet
Dim crng As Range, cValues()
Set crng = Intersect(ws.UsedRange.Offset(1, 0), ws.UsedRange, ws.Range("D:D"))
cValues = crng.Value
Dim i As Long, j As Long
For i = LBound(cValues) To UBound(cValues)
For j = LBound(cValues, 2) To UBound(cValues, 2)
cValues(i, j) = Left(cValues(i, j), 5)
Next j
Next i
'for same sheet different column
ws.Range("F2").Resize(UBound(cValues), UBound(cValues, 2)) = Application.Transpose(cValues)
'different sheet
Sheets("Sheet2").Range("F2").Resize(UBound(cValues), UBound(cValues, 2)) = Application.Transpose(cValues)
'different file
Workbooks("Zip Code Question.xlsb").Sheets("Sheet3").Range("F2").Resize(UBound(cValues), UBound(cValues, 2)) = Application.Transpose(cValues)
End Sub
Copy Entire Rows If Criteria Met
Option Explicit
Sub Postal5()
' Define constants.
Const srcName As String = "Sheet2"
Const srcFirst As String = "D2"
Const dstName As String = "Sheet3"
Const dstFirst As String = "A2" ' do not change the 'A' (entire row).
Const pLen As Long = 5
' Define workbook.
Dim wb As Workbook: Set wb = ThisWorkbook ' Workbook containing this code.
' Define Source Range.
Dim LastRow As Long
Dim srg As Range
With wb.Worksheets(srcName).Range(srcFirst)
LastRow = .Offset(.Worksheet.Rows.Count - .Row).End(xlUp).Row
Set srg = .Resize(LastRow - .Row + 1)
End With
' 'Combine' critical cells into a range.
Dim brg As Range ' Built Range
Dim cel As Range ' Current Cell Range
For Each cel In srg.Cells
If Len(cel.Value) > pLen Then
If brg Is Nothing Then
Set brg = cel
Else
Set brg = Union(brg, cel)
End If
End If
Next cel
If brg Is Nothing Then Exit Sub
Application.ScreenUpdating = False
' Copy and delete critical rows of Source Range.
With wb.Worksheets(dstName).Range(dstFirst)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
.Worksheet.Columns.Count).Clear
Set brg = brg.EntireRow ' 'Convert' cells into rows.
brg.Copy .Offset ' Copy. 'Offset' because range is in 'With'.
brg.Delete ' Delete.
End With
Application.ScreenUpdating = False
End Sub
Text the next code, please. It uses arrays and it should be very fast for a big range:
Sub testSplitZiPCodeStrings()
Dim sh2 As Worksheet, sh3 As Worksheet, lastR As Long
Dim i As Long, arr, arrZip, arrNoZip, kZ As Long, kN As Long
Set sh2 = ActiveSheet ' Worksheets("Sheet2")
Set sh3 = sh2.Next ' Worksheets("Sheet3")
lastR = sh2.Range("D" & sh2.Rows.count).End(xlUp).row 'last row
arr = sh2.Range("D2:D" & lastR).Value 'put the range in an array
ReDim arrZip(UBound(arr) - 1) 'redim the array to surely have place for all elements
ReDim arrNoZip(UBound(arr) - 1) 'redim the array to surely have place for all elements
For i = 1 To UBound(arr) ' iterate between the array elements
If Len(arr(i, 1)) = 5 Then
arrZip(kZ) = arr(i, 1): kZ = kZ + 1
Else
arrNoZip(kN) = arr(i, 1): kN = kN + 1
End If
Next i
ReDim Preserve arrZip(kZ - 1) 'keep only the array elements having values
ReDim Preserve arrZip(kN - 1) 'keep only the array elements having values
sh2.Range("D2:D" & lastR).Clear 'Clear the initial range
'Drop the Zip array content at once:
sh2.Range("D2").Resize(UBound(arrZip), 1).Value = Application.Transpose(arrZip)
'Drop the NoZip array content at once:
sh3.Range("D2").Resize(UBound(arrNoZip), 1).Value = Application.Transpose(arrNoZip)
End Sub
Here's 2 samples. The first one is more intuitive and uses ranges. The second one is less intuitive but faster by using arrays.
Simple but Slower:
'The easy way, but can be slow if you have lots of zip codes
Sub TrimRange()
Dim InputWorksheet As Worksheet, OutputWorksheet As Worksheet
Dim RangeInput As Range, RangeOutput As Range, Column As Range
Dim HeaderRow As Integer, ColumnNumber As Integer, LastRow As Integer, i As Integer
Dim OutputColumn As Range
Dim ColumnFound As Boolean
Dim fullzipcode As String
Set InputWorksheet = Worksheets("Sheet2")
Set OutputWorksheet = Worksheets("Sheet3")
HeaderRow = 1
'Get Input and Output Range
ColumnNumber = 0
ColumnFound = False
For Each Column In InputWorksheet.Columns
ColumnNumber = ColumnNumber + 1
If Column.Cells(HeaderRow, 1) = "postalcode" Then
LastRow = Column.End(xlDown).Row
'I assume the Output column will be in the same position as the input column
Set OutputColumn = OutputWorksheet.Columns(ColumnNumber)
'If OutputColumn is always in Column 'D' then replace previous line with:
'Set OutputColumn = OutputWorksheet.Columns(4)
Set RangeInput = InputWorksheet.Range(Column.Cells(HeaderRow + 1, 1), Column.Cells(LastRow, 1))
Set RangeOutput = OutputWorksheet.Range(OutputColumn.Cells(HeaderRow + 1, 1), OutputColumn.Cells(LastRow, 1))
ColumnFound = True
Exit For
End If
Next
If ColumnFound Then
'Initialize Interior color to nothing
'and remove values from output column
RangeInput.Interior.ColorIndex = 0
RangeOutput.ClearContents
'Change values and formatting
For i = 1 To RangeInput.Rows.Count
fullzipcode = RangeInput.Cells(i, 1).Value
If Len(fullzipcode) > 5 Then
RangeInput.Cells(i, 1).Interior.Color = RGB(255, 0, 0)
RangeInput.Cells(i, 1).Value = Left(fullzipcode, 5)
End If
RangeOutput.Cells(i, 1).Value = fullzipcode
Next
End If
End Sub
Faster but Less Intuitive
'The harder way, but faster
Sub TrimRange2()
Dim InputWorksheet As Worksheet, OutputWorksheet As Worksheet
Dim RangeInput As Range, RangeOutput As Range, Column As Range
Dim HeaderRow As Integer, ColumnNumber As Integer, LastRow As Integer, i As Integer
Dim InputValues() As Variant, OutputValues() As Variant
Dim OutputColumn As Range
Dim ColumnFound As Boolean
Dim fullzipcode As String
Set InputWorksheet = Worksheets("Sheet2")
Set OutputWorksheet = Worksheets("Sheet3")
HeaderRow = 1
'Get Input and Output Range
ColumnNumber = 0
ColumnFound = False
For Each Column In InputWorksheet.Columns
ColumnNumber = ColumnNumber + 1
If Column.Cells(HeaderRow, 1) = "postalcode" Then
LastRow = Column.End(xlDown).Row
'I assume the Output column will be in the same position as the input column
Set OutputColumn = OutputWorksheet.Columns(ColumnNumber)
'If OutputColumn is always in Column 'D' then replace previous line with:
'Set OutputColumn = OutputWorksheet.Columns(4)
Set RangeInput = InputWorksheet.Range(Column.Cells(HeaderRow + 1, 1), Column.Cells(LastRow, 1))
Set RangeOutput = OutputWorksheet.Range(OutputColumn.Cells(HeaderRow + 1, 1), OutputColumn.Cells(LastRow, 1))
ColumnFound = True
Exit For
End If
Next
If ColumnFound Then
'Initialize Interior color to nothing
'and remove values from output column
RangeInput.Interior.ColorIndex = 0
RangeOutput.ClearContents
'Initialize Arrays (much faster than working with ranges)
InputValues = RangeInput.Value2
OutputValues = RangeOutput.Value2
'Change values and formatting
For i = 1 To RangeInput.Rows.Count
fullzipcode = InputValues(i, 1)
If Len(fullzipcode) > 5 Then
RangeInput.Cells(i, 1).Interior.Color = RGB(255, 0, 0)
InputValues(i, 1) = Left(fullzipcode, 5)
End If
OutputValues(i, 1) = fullzipcode
Next
'Save arrays to ranges
RangeInput.Value2 = InputValues
RangeOutput.Value2 = OutputValues
End If
End Sub

Select used rows within a Named Range?

I have an Excel Named Range called Schd_Preview which consists of cells F3:K500. Sometimes only 2 or 3 rows are used, sometimes 200 rows are used, sometimes all the rows are used. How do I copy only used rows within Schd_Preview within VBA?
Edit: I have data to the left of Schd_Preview in range B2:C12. Intersect() will not work with .UsedRange since it will include, at the very minimum, row 12 even if the named range only uses 2 rows.
Used Rows Within Range
NonCont and Cont refer to the used rows i.e. are they contiguous.
The first solution will not work if you have hidden used rows.
The Code
Option Explicit
Sub NonCont1() ' Values, formulas, formats.
Const PasteCell As String = "M3"
With Range(PasteCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
Range("Schd_Preview").Columns.Count).Clear
End With
Dim rng As Range ' Copy Range
Set rng = Range("Schd_Preview").SpecialCells(xlCellTypeVisible)
rng.Copy Range(PasteCell) ' If you need values, then use 'PasteSpecial'.
' rng.Copy
' Range(PasteCell).PasteSpecial xlPasteValues
' Application.CutCopyMode = False
End Sub
Sub NonCont2() ' Values only.
Const PasteCell As String = "M3"
Const LastRowCol As Long = 1 ' in your case 1-6 (F-K).
Dim Data As Variant
Data = Range("Schd_Preview").Value
Dim UB2 As Long
UB2 = UBound(Data, 2)
Dim i As Long
Dim j As Long
Dim k As Long
For i = 1 To UBound(Data, 1)
If Data(i, LastRowCol) <> "" Then
k = k + 1
For j = 1 To UB2
Data(k, j) = Data(i, j)
Next j
End If
Next i
With Range(PasteCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, UB2).Clear
Dim rng As Range ' Paste Range
Set rng = .Resize(k, UB2)
End With
rng.Value = Data
End Sub
' Surrounded by empty rows and columns.
Sub cont1()
Const PasteCell As String = "M3"
With Range(PasteCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
Range("Schd_Preview").Columns.Count).Clear
End With
Dim rng As Range ' Copy Range
Set rng = Range("Schd_Preview").Cells(1).CurrentRegion
rng.Copy Range(PasteCell) ' Values, formulas, formats.
'Range(PasteCell).Resize(rng.Rows.Count, rng.Columns.Count).Value _
= rng.Value ' Values only.
End Sub
' Empty column to the right, and empty row at the bottom.
Sub cont2()
Const PasteCell As String = "M3"
With Range(PasteCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
Range("Schd_Preview").Columns.Count).Clear
End With
Dim cel As Range
Set cel = Range("Schd_Preview").Cells(1)
Dim rng As Range ' Copy Range
Set rng = Range("Schd_Preview").Cells(1).CurrentRegion
With rng
Set rng = .Resize(.Rows.Count + .Row - cel.Row, _
.Columns.Count + .Column - cel.Column) _
.Offset(cel.Row - .Row, cel.Column - .Column)
End With
rng.Copy Range(PasteCell) ' Values, formulas, formats.
'Range(PasteCell).Resize(rng.Rows.Count, rng.Columns.Count).Value _
= rng.Value ' Values only.
End Sub
Sub cont3() ' Values only. It's a simplified 'NonCont2'.
Const PasteCell As String = "M3"
Const LastRowCol As Long = 1 ' in your case 1-6 (F-K).
Dim Data As Variant
Data = Range("Schd_Preview").Value
Dim UB2 As Long
UB2 = UBound(Data, 2)
Dim i As Long
For i = 1 To UBound(Data, 1)
If Data(i, LastRowCol) = "" Then
Exit For
End If
Next i
With Range(PasteCell)
.Resize(.Worksheet.Rows.Count - .Row + 1, UB2).Clear
Dim rng As Range ' Paste Range
Set rng = .Resize(i - 1, UB2)
End With
rng.Value = Data
End Sub

Resources