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
Related
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
Hello I have an excel program that filters my table when I copy/paste my references in column J. However depending on where I copied the references it doesn't work.
VBA tells me this : Selection.SpecialCells(xlCellTypeConstants, 2)
I do not understand why.
Here is my program:
Sub DoMyFilter()
Columns("A:J").Select
Selection.NumberFormat = "#"
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim cell As Range
For Each cell In _
Selection.SpecialCells(xlCellTypeConstants, 1)
cell.Value = cell.Text
Next cell
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Dim vCrit As Variant
Dim aCrit As Variant
vCrit = Range("J2:J100000").Value
aCrit = Application.Transpose(vCrit)
ActiveSheet.Range("$A$1:$H$7634").AutoFilter Field:=1, Criteria1:=aCrit, Operator:=xlFilterValues
Range("J:J").ClearContents
End Sub
Can anyone help me ?
Filter on a 'Bunch of Values'
Adjust the values in the constants section.
Option Explicit
Sub DoMyFilter()
Const dCols As String = "A:H" ' Destination Columns Range
Const dFirst As Long = 1 ' Destination First Row
Const dField As Long = 1 ' Destination Criteria Field (Column)
Const cCol As String = "J" ' Criteria Column
Const cFirst As Long = 2 ' Criteria First Row
' Turn off possibly applied AutoFilter.
Dim ws As Worksheet: Set ws = ActiveSheet
If ws.AutoFilterMode Then
ws.AutoFilterMode = False
End If
' Define Criteria Column Range.
Dim crg As Range ' Criteria Last Cell
With ws.Columns(cCol)
Dim cCell As Range
Set cCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If cCell Is Nothing Then Exit Sub ' Validate.
If cCell.Row < cFirst Then Exit Sub ' Validate.
Set crg = .Resize(cCell.Row - cFirst + 1).Offset(cFirst - 1)
End With
'Debug.Print crg.Address
' Write values from Criteria Column Range to 2D one-based Data Array.
Dim crCount As Long: crCount = crg.Rows.Count
Dim Data As Variant
If crCount = 1 Then
ReDim Data(1 To 1, 1 To 1): Data = crg.Value
Else
Data = crg.Value
End If
' Write unique values, except error values and blanks, from Data Array
' to Unique Dictionary and to 1D zero-based Criteria Array.
' The dictionary is used to remove duplicates.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim Criteria() As String: ReDim Criteria(0 To crCount - 1)
Dim n As Long: n = -1 ' Criteria Array Elements Counter
Dim Key As Variant ' Value of Current Element in Data Array
Dim r As Long ' Data Array Rows Counter
For r = 1 To crCount
Key = Data(r, 1)
If Not IsError(Key) Then
If Len(Key) > 0 Then
Key = CStr(Key)
If Not dict.Exists(Key) Then
n = n + 1
Criteria(n) = Key
dict(Key) = Empty
End If
End If
End If
Next r
Set dict = Nothing
Erase Data
If n = -1 Then Exit Sub ' Validate.
ReDim Preserve Criteria(0 To n)
' Define Destination Range.
Dim drg As Range
With ws.Columns(dCols)
Dim dCell As Range ' Destination Last Cell
Set dCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If dCell Is Nothing Then Exit Sub ' Validate.
If dCell.Row < dFirst Then Exit Sub ' Validate.
Set drg = .Resize(dCell.Row - dFirst + 1)
End With
'Debug.Print drg.Address
' Turn off application settings.
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' Apply AutoFilter.
drg.AutoFilter Field:=dField, Criteria1:=Criteria, Operator:=xlFilterValues
' Clear contents of Criteria Column.
'ws.columns(cCol).ClearContents ' ???
' Turn on application settings.
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
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
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
I want to refer to a range of cells across columns: B:C then E:M (skipping D). I want to copy the cells and paste them to another worksheet.
I have a For Next loop with the row number variable iT. How do I select them using the variable?
This selects the whole range including D.
Sheet4.Range("B" & iT & ":C" & iT, "E" & iT & ":M" & iT).Select
I tried Cells().
Try this
Sht.range("A:M").copy AnotherWorkbook.sheets("YourSheet").range("A1")
AnotherWorkbook.sheets("YourSheet").range("D:D").delete
A Brief Study
Copy Values, Formats, Formulas
Sub NonContiguousRow()
Dim iT As Long
iT = 1
Dim cols As Range
Set cols = Sheet1.Range("B:C,E:M")
' Optionally:
'Set cols = Union(Sheet1.Columns("B:C"), Sheet1.Columns("E:M"))
Dim rRng As Range
Set rRng = Intersect(Sheet1.Rows(iT), cols)
rRng.Copy Sheet2.Cells(1, "A")
' This will also work:
'Dim ColumnsCount As Long
'ColumnsCount = getColumnsCount(cols)
'rRng.Copy Sheet2.Cells(1, "A").Resize(, ColumnsCount)
' This will NOT work:
'Sheet2.Cells(1, "A").Resize(, ColumnsCount).Value = rRng.Value
End Sub
Function getColumnsCount( _
aRange As Range) _
As Long
If Not aRange Is Nothing Then
Dim rng As Range
For Each rng In aRange.Areas
getColumnsCount = getColumnsCount + rng.Columns.Count
Next rng
End If
End Function
Copy Values
Sub TESTgetRow()
Dim iT As Long
iT = 1
Dim cols As Range
Set cols = Sheet1.Range("B:C,E:M")
Dim Data As Variant
Data = getRow(cols, iT)
Sheet2.Cells(1, "A").Resize(, UBound(Data) - LBound(Data) + 1).Value = Data
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the values at the intersection of a range
' and one of its worsheet's rows, in an array.
' Remarks: Supports non-contiguous ranges.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getRow( _
aRange As Range, _
Optional ByVal aRow As Long = 1) _
As Variant
If Not aRange Is Nothing Then
Dim rRng As Range
Set rRng = Intersect(aRange, aRange.Worksheet.Rows(aRow))
If Not rRng Is Nothing Then
With CreateObject("Scripting.Dictionary")
Dim rng As Range
Dim cel As Range
Dim n As Long
For Each rng In rRng.Areas
For Each cel In rng.Cells
n = n + 1
.Item(n) = cel.Value
Next cel
Next rng
getRow = .Items
End With
Else
' Row range is empty ('Nothing').
End If
Else
' Range is empty ('Nothing').
End If
End Function
If you want to use Cells Method.
Sub CopyUsingCellsMethod()
Dim ColumnNumber As Long
Dim RowNumber As Long
RowNumber = 1 'Enter Your Required Row Number Here
With ThisWorkbook.Worksheets("Sheet4")
For ColumnNumber = 2 To 5 Step 3 'This would Copy Range(B1:C1) into Range(I1:J1) and Then Range(E1:F1) into Range(L1:M1)
.Range(Cells(RowNumber, ColumnNumber), Cells(RowNumber, ColumnNumber + 1)).Copy Worksheets("Sheet4").Range(.Cells(RowNumber, ColumnNumber + 7), .Cells(RowNumber, ColumnNumber + 8))
Next ColumnNumber
End With
End Sub