I want to highlight cells with the largest value in each row but only using columns F, I, L, O and R.
Sub Highlights()
Dim ws As Worksheet
Dim ColorRng As Range
Dim ColorCell As Range
Set ws = Worksheets("Sheet2")
Set ColorRng = ws.Range("F7,I7,L7,O7,R7")
'highlight the cell that contains the highest and lowest number
For Each ColorCell In ColorRng
If ColorCell.Value = Application.WorksheetFunction.Max(ColorRng) Then
ColorCell.Interior.Color = RGB(0, 180, 40)
ElseIf ColorCell.Value = Application.WorksheetFunction.Min(ColorRng) Then
ColorCell.Interior.Color = RGB(255, 0, 0)
End If
Next
End Sub
It works for the first row (that being row 7), but it doesn't continue to the next row. I realize this is because of my ColorRng range.
How do I allow the range to include more?
Please try this code.
Sub SetHighlights()
Dim ColorRng As Range
Dim ColorCell As Range ' loop object
Dim Mini As Variant
Dim Maxi As Variant
Dim R As Long ' loop counter: rows
Dim C As Long ' loop counter: columns
Dim n As Integer ' result counter
'highlight the cell that contains the highest and lowest number
Application.ScreenUpdating = False
With Worksheets("Sheet2")
For R = 2 To .Cells(.Rows.Count, "F").End(xlUp).Row
Set ColorRng = Union(.Cells(R, "F"), .Cells(R, "I"), _
.Cells(R, "L"), .Cells(R, "R"))
Mini = Application.Min(ColorRng)
Maxi = Application.Max(ColorRng)
For Each ColorCell In ColorRng
With ColorCell
If .Value = Maxi Then
.Interior.Color = RGB(0, 180, 40)
n = n + 1
ElseIf .Value = Mini Then
.Interior.Color = RGB(255, 0, 0)
n = n + 1
End If
End With
If n = 2 Then Exit For
Next ColorCell
Next R
End With
Application.ScreenUpdating = True
End Sub
Observe that the Min and Max functions are run only once per row instead of for each cell as your original code had it. Turning off ScreenUpdating further enhances the speed with which the procedure can complete the job
Give a try on below sub. As you need to highlight in every row, so you have to iterate every row to compare.
Sub Highlights()
Dim ws As Worksheet
Dim ColorRng As Range
Dim ColorCell As Range
Dim lRow As Long
Set ws = Worksheets("Sheet2")
lRow = ws.Cells(ws.Rows.Count, "F").End(xlUp).Row
With ws
For i = 7 To lRow
Set ColorRng = Union(.Range("F" & i), .Range("I" & i), .Range("L" & i), .Range("O" & i), .Range("R" & i))
For Each ColorCell In ColorRng
If ColorCell.Value = Application.Max(ColorRng) Then
ColorCell.Interior.Color = RGB(0, 180, 40)
ElseIf ColorCell.Value = Application.Min(ColorRng) Then
ColorCell.Interior.Color = RGB(255, 0, 0)
End If
Next ColorCell
Set ColorRng = Nothing
Next i
End With
End Sub
Highlight Mins and Maxes
If error values, it will fail.
If no numeric value, then no color.
If max = min, then max color.
Adjust the values in the constants section.
The Code
Option Explicit
Sub highlightMinMax()
Const wsName As String = "Sheet2"
Const FirstRow As Long = 7
Const LastRowColumn As String = "F"
Const ColsList As String = "F,I,L,O,R"
Dim ColorMin As Long: ColorMin = RGB(255, 0, 0) ' 255
Dim ColorMax As Long: ColorMax = RGB(0, 180, 40) ' 2667520
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim rgCols As Range
Dim LastRow As Long
Dim i As Long
Set rgCols = ws.Columns(LastRowColumn)
LastRow = ws.Cells(ws.Rows.Count, LastRowColumn).End(xlUp).Row
If LastRow < FirstRow Then Exit Sub
Dim Cols() As String: Cols = Split(ColsList, ",")
For i = 0 To UBound(Cols)
Set rgCols = getCombinedRangeBasic(rgCols, ws.Columns(Cols(i)))
Next i
Erase Cols
Dim rgColor As Range
Dim cel As Range
Dim rgMin As Range
Dim rgMax As Range
Dim cMin As Double
Dim cMax As Double
For i = FirstRow To LastRow
Set rgColor = Intersect(rgCols, ws.Rows(i))
cMax = Application.Max(rgColor)
cMin = Application.Min(rgColor)
For Each cel In rgColor
If cel.Value = cMax Then
Set rgMax = getCombinedRangeBasic(rgMax, cel)
ElseIf cel.Value = cMin Then
Set rgMin = getCombinedRangeBasic(rgMin, cel)
End If
Next
Next i
If Not rgMin Is Nothing Then
rgMin.Interior.Color = ColorMin
End If
If Not rgMax Is Nothing Then
rgMax.Interior.Color = ColorMax
End If
End Sub
Function getCombinedRangeBasic( _
ByVal BuiltRange As Range, _
ByVal AddRange As Range)
If BuiltRange Is Nothing Then
Set getCombinedRangeBasic = AddRange
Else
Set getCombinedRangeBasic = Union(BuiltRange, AddRange)
End If
End Function
This proposed solution uses FormatConditions
FormatConditions will keep the Mins & Maxs updated when ever the values get changed.
Only need to rerun the procedure when the range changes.
However, FormatConditions are Volatile therefore need to evaluate the size of your data.
…
Sub FormatConditions_MinMax_NonContiguousRow()
Const kIni As Byte = 7
Dim Rng As Range, rRow As Range, lRow As Long
With ThisWorkbook.Sheets("Sheet2") 'Change as required
Rem Disable AutoFilter
If Not (.AutoFilter Is Nothing) Then .AutoFilter.Range.AutoFilter
Rem Set & Validate Last Row
lRow = .Columns("F").Cells(.Rows.Count).End(xlUp).Row
If lRow <= kIni Then Exit Sub
Rem Set Data Range
Set Rng = .Range("F" & kIni & ":R" & lRow)
End With
With Rng
Rem Delete prior FormatConditions
.FormatConditions.Delete
Rem Add FormatConditions by Row
For Each rRow In .Rows
With rRow
Rem Add FormatConditions Max
With .FormatConditions.AddTop10
.SetFirstPriority
.TopBottom = xlTop10Top
.Rank = 1
.Percent = False
.Interior.Color = RGB(255, 0, 0)
.StopIfTrue = True
End With
Rem FormatConditions Min
With .FormatConditions.AddTop10
.SetFirstPriority
.TopBottom = xlTop10Bottom
.Rank = 1
.Percent = False
.Interior.Color = RGB(0, 180, 40)
.StopIfTrue = True
End With
End With: Next
Rem Remove FormatConditions from Other Columns
Application.Intersect(.Cells, Range("G:H,J:K,M:N,P:Q")).FormatConditions.Delete
.Calculate
End With
End Sub
Related
I'm working on a macro that highlighted & colors the empty cells in a specific column (AE), but I need to clear this color-highlighted based on a result that exists in the column (AD)
If AD column, cells value = "SPLICE" clear color, If Empty the color should exist, below picture explains more.
I use the code below
Sub EmptyTerminalTO()
Application.ScreenUpdating = False
Sheets("Wire List").Activate
Dim i As Long
Dim c As Long
Dim myRange As Range
Dim myCell As Range
Set myRange = Range("AD2", Range("AD" & Rows.Count).End(xlUp))
For Each myCell In myRange '
c = c + 1
If (myCell) = "" Then
myCell.Interior.Color = RGB(255, 87, 87)
i = i + 1
End If
Next myCell
Rapport8 = i
Application.ScreenUpdating = True
End Sub
try using offset as per code below:
Option Explicit
Sub EmptyTerminalTO()
Application.ScreenUpdating = False
Sheets("Wire List").Activate
Dim i As Long
Dim c As Long, Rapport8 As Long
Dim myRange As Range
Dim myCell As Range
Set myRange = Range("AD2", Range("AD" & Rows.Count).End(xlUp))
For Each myCell In myRange '
c = c + 1
If myCell <> "SPLICE" & myCell.Offset(0, 1)="" Then
myCell.Offset(0, 1).Interior.Color = RGB(255, 87, 87)
Else
myCell.Offset(0, 1).Interior.Pattern = xlNone
i = i + 1
End If
Next myCell
Rapport8 = i
End Sub
I am trying to extract listobject filtered data to a new workbook. However, all data is extracted instead of just the filtered data.
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
ColNum = Application.WorksheetFunction.Match("DateOrder", wsCopy.Rows(1), 0)
With loop_obj
.Range.AutoFilter Field:=ColNum, Criteria1:=">=0"
End With
'Add Copy Values to Array
Set loop_copy = loop_obj.AutoFilter.Range.SpecialCells(xlCellTypeVisible)
arr = loop_copy.CurrentRegion.Offset(1, 0)
aRws = Evaluate("Row(1:" & UBound(arr) & ")")
arr = Application.Index(arr, aRws, Array(1, 2, 3, 4, 5))
'Create New Workbook with a Blank Worksheet
wb.Worksheets.Add.Move
Set wb_new = ActiveWorkbook
Set wsDest = ActiveWorkbook.ActiveSheet
'Perform Paste Operations
Set loop_paste = wsDest.Range("A1")
loop_paste.Resize(UBound(arr, 1), UBound(arr, 2)).value = arr
With wsDest
.Range(Cells(1, DateNum), Cells(1200, DateNum)).NumberFormat = "[$-en-US]d-mmm-yy;#"
.Parent.SaveAs FileName:=dFilePath, FileFormat:=xlCSVUTF8
.Parent.Close True
End With
loop_obj.AutoFilter.ShowAllData
This worked for me (just copy each column based off the array of column indexes):
Sub tester()
Dim wsCopy As Worksheet, loop_copy As Range
Dim loop_obj As ListObject, colnum As Long
Dim col, visRows As Long, rngDest As Range, i As Long
Set wsCopy = Sheets("Details")
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
colnum = Application.Match("DateOrder", loop_obj.HeaderRowRange, 0)
If IsError(colnum) Then
MsgBox "Header not found!"
Exit Sub
End If
Application.ScreenUpdating = False
loop_obj.Range.AutoFilter Field:=colnum, Criteria1:=">=0"
On Error Resume Next 'in case no visible rows to count
visRows = loop_obj.DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
On Error GoTo 0
If visRows > 0 Then
Set rngDest = Sheets("destination").Range("B2")
i = 0
For Each col In Array(1, 2, 3, 4, 5)
loop_obj.DataBodyRange.Columns(col).SpecialCells(xlCellTypeVisible).Copy
rngDest.Parent.Paste Destination:=rngDest.Offset(0, i)
i = i + 1
Next col
End If
loop_obj.AutoFilter.ShowAllData
End Sub
EDIT: a different array-based approach - this is faster, but again it's more complex, so there's a trade-off.
Sub Tester()
Dim wsCopy As Worksheet, loop_copy As Range
Dim loop_obj As ListObject, colnum As Long
Dim col, visRows As Long, rngDest As Range, i As Long, data
Set wsCopy = Sheets("Details")
Set loop_obj = wsCopy.ListObjects(1)
loop_obj.AutoFilter.ShowAllData
colnum = Application.Match("DateOrder", loop_obj.HeaderRowRange, 0)
If IsError(colnum) Then
MsgBox "Header not found!"
Exit Sub
End If
Application.ScreenUpdating = False
loop_obj.Range.AutoFilter Field:=colnum, Criteria1:=">=0"
data = arrayFromVisibleRows(loop_obj.DataBodyRange)
If Not IsEmpty(data) Then
With Sheets("Destination").Range("B2")
.CurrentRegion.ClearContents
.Resize(UBound(data, 1), UBound(data, 2)).Value = data
End With
End If
loop_obj.AutoFilter.ShowAllData
End Sub
'Return a 2D array using only visible row in `rng`
' Optionally include only column indexes in `cols` (passed as a 1D array)
Function arrayFromVisibleRows(rng As Range, Optional cols As Variant = Empty)
Dim rngVis As Range, data, dataOut
Dim rw As Long, col, e, c As Range, cOut As Long, rOut As Long, srcRow As Long
On Error Resume Next
Set rngVis = rng.Columns(1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rngVis Is Nothing Then
data = rng.Value 'read all the range data to an array
If IsEmpty(cols) Then
'create an array with all column indexes if none were provided
cols = Application.Transpose(Evaluate("=ROW(1:" & rng.Columns.Count & ")"))
End If
'size the output array
ReDim dataOut(1 To rngVis.Cells.Count, 1 To (UBound(cols) - LBound(cols)) + 1)
rOut = 1
For Each c In rngVis.Cells
cOut = 1
srcRow = 1 + (c.Row - rng.Cells(1).Row)
For Each col In cols 'loop the required columns
dataOut(rOut, cOut) = data(srcRow, col)
cOut = cOut + 1
Next col
rOut = rOut + 1
Next c
arrayFromVisibleRows = dataOut
Else
arrayFromVisibleRows = Empty
End If
End Function
I think that this is close to what the OP wants. I didn't bother saving the file because its not relevant to my test and I added column headers.
Sub Main()
Dim tCopyTable As ListObject
Set tCopyTable = wsCopy.ListObjects(1)
Dim DateOrder As ListColumn
Dim Source As Range
With tCopyTable
If Not .AutoFilter Is Nothing Then .AutoFilter.ShowAllData
Set DateOrder = tCopyTable.ListColumns("DateOrder")
.Range.AutoFilter Field:=DateOrder.Index, Criteria1:=">=0"
Set Source = .Range.Offset(1)
End With
Dim CountOfVisibleDates As Long
CountOfVisibleDates = WorksheetFunction.Subtotal(103, Source.Columns(DateOrder.Index))
If CountOfVisibleDates > 0 Then
Dim wb As Workbook
Set wb = Workbooks.Add
With wb.Worksheets(1)
tCopyTable.HeaderRowRange.Resize(1, 5).Copy .Range("A1")
Source.Resize(, 5).Copy .Range("A2")
End With
End If
End Sub
Note: Looping through the values is almost always much faster than copying ranges.
Addendum
Sub Main2()
Dim tCopyTable As ListObject
Set tCopyTable = wsCopy.ListObjects(1)
Dim DateOrder As ListColumn
Dim Source As Range
With tCopyTable
If Not .AutoFilter Is Nothing Then .AutoFilter.ShowAllData
Set DateOrder = tCopyTable.ListColumns("DateOrder")
.Range.AutoFilter Field:=DateOrder.Index, Criteria1:=">=0"
Set Source = .Range.Offset(1)
End With
Dim CountOfVisibleDates As Long
CountOfVisibleDates = WorksheetFunction.Subtotal(103, Source.Columns(DateOrder.Index))
Dim OriginalColumnOrder As Variant
Dim NewColumnOrder As Variant
OriginalColumnOrder = Array(1, 2, 3, 4, 5)
NewColumnOrder = Array(3, 2, 1, 5, 4)
Dim c As Long
If CountOfVisibleDates > 0 Then
Dim wb As Workbook
Set wb = Workbooks.Add
With wb.Worksheets(1)
For c = 0 To UBound(NewColumnOrder)
tCopyTable.HeaderRowRange.Columns(OriginalColumnOrder(c)).Copy .Rows(1).Columns(NewColumnOrder(c))
Source.Resize(, 5).Columns(OriginalColumnOrder(c)).Copy .Rows(2).Columns(NewColumnOrder(c))
Next
End With
End If
End Sub
Result
I was in a rush. This is all that is needed to copy the headers and filtered data:
tCopyTable.ListColumns(OriginalColumnOrder(c)).Range.Copy .Rows(1).Columns(NewColumnOrder(c))
If you just want the data use:
tCopyTable.ListColumns(OriginalColumnOrder(c)).DataBodyRange.Copy .Rows(1).Columns(NewColumnOrder(c))
I have a list of items with data from Column L to X and I would like to add the total of each row in the above range in the corresponding row in column K.
In order to do that I wrote the following code but there is no output and no errors:
Sub Sum_multiple_columns()
Dim ws As Worksheet
Dim destinationLastRow As Long, i As Long
Dim TotalCoverage As Double
Dim rng As Range, MyResultsRng As Range
Const FirstCol As Long = 10 ' "L"
Const LastCol As Long = 22 ' "X"
Const TotalCoverageColumn As Long = 9
Set ws = ThisWorkbook.Worksheets("Master")
destinationLastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For i = 5 To destinationLastRow
Set MyResultsRng = ws.Range("K" & i)
For Each cell In MyResultsRng
Set rng = ws.Range(ws.Cells(i, FirstCol), ws.Cells(i, LastCol))
TotalCoverage = Application.WorksheetFunction.Sum(rng.Value)
Next
Next
With MyResultsRng
.Value = TotalCoverage
.HorizontalAlignment = xlCenter
.Interior.Color = RGB(0, 112, 192)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
.Font.Size = 12
.Font.Name = "Calibri"
.NumberFormat = "0.00"
End With
End Sub
Thank you in advance for pointing me towards the right direction.
Thank you
Sum Rows of Adjacent Columns
Option Explicit
Sub SumRowsOfAdjacentColumns()
Const wsName As String = "Master" ' Worksheet Name
Const fRow As Long = 5 ' First Row
Const sCols As String = "L:X" ' Source (Sum) Columns
Const lrCol As String = "A" ' Last Row Column
Const tCol As String = "K" ' Totals (Destination) Column
' Create a reference to the workbook.
Dim wb As Workbook: Set wb = ThisWorkbook
' Create a reference to the worksheet.
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
' Create a reference to the Totals Range ('trg').
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, lrCol).End(xlUp).Row
If lRow < fRow Then Exit Sub ' no data
Dim rCount As Long: rCount = lRow - fRow + 1
Dim trg As Range: Set trg = ws.Cells(fRow, tCol).Resize(rCount)
'Debug.Print "Totals Range Address: " & trg.Address(0, 0)
Dim srrg As Range ' Current Source Row (Sum) Range
Dim tCell As Range ' Current Totals Cell
Dim TotalCoverage As Variant ' Current Total ***
Dim sCell As Range ' Current Source Cell (If Error Values)
Dim tSum As Double ' Current Subtotal (If Error Values)
For Each tCell In trg.Cells
' Use the current Totals Cell ('tCell') to create a reference
' to the current Source Row (Sum) Range ('srrg').
Set srrg = tCell.EntireRow.Columns(sCols)
'Debug.Print "Source Row Range Address: " & srrg.Address(0, 0)
' If there are error values, 'WorksheetFunction.Sum' will raise
' an error, while 'Application.Sum' will return an error value.
' Hence the previous declaration 'As Variant' is necessary ***.
TotalCoverage = Application.Sum(srrg)
If IsNumeric(TotalCoverage) Then ' no error values
tCell.Value = TotalCoverage
Else ' there are error values
tSum = 0
For Each sCell In srrg.Cells
' Sum-up only numeric values.
If IsNumeric(sCell) Then
tSum = tSum + sCell.Value
End If
Next sCell
tCell.Value = tSum
End If
Next tCell
' Formatting the cells in one go is more efficient (faster).
With trg
.HorizontalAlignment = xlCenter
.Interior.Color = RGB(0, 112, 192)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
.Font.Size = 12
.Font.Name = "Calibri"
.NumberFormat = "0.00"
'.EntireColumn.AutoFit
End With
End Sub
You update the value of TotalCoverage on each pass in the loop. After the loop has finished you put the final value of TotalCoverage onto the sheet.
As it is your code didn't run as you've not declared the cell variable - one of the benefits of having Option Explicit at the top of the module. Reminds you to declare all variables.
With data going from L5:X13 it places the result in cell K13. To get it to place a total on each row use the code below.
Only difference is where the two Next statements are. I've also declared cell and added which loop the Next belongs to (i.e. Next cell).
Sub Sum_multiple_columns()
Dim ws As Worksheet
Dim destinationLastRow As Long, i As Long
Dim TotalCoverage As Double
Dim rng As Range, MyResultsRng As Range
Dim cell As Range
Const FirstCol As Long = 12 ' "L"
Const LastCol As Long = 24 ' "X"
Const TotalCoverageColumn As Long = 9
Set ws = ThisWorkbook.Worksheets("Master")
destinationLastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For i = 5 To destinationLastRow
Set MyResultsRng = ws.Range("K" & i)
For Each cell In MyResultsRng
Set rng = ws.Range(ws.Cells(i, FirstCol), ws.Cells(i, LastCol))
TotalCoverage = Application.WorksheetFunction.Sum(rng.Value)
With cell
.Value = TotalCoverage
.HorizontalAlignment = xlCenter
.Interior.Color = RGB(0, 112, 192)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
.Font.Size = 12
.Font.Name = "Calibri"
.NumberFormat = "0.00"
End With
Next cell
Next i
End Sub
Edit: Have also changed With MyResultRng to With Cell.
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 have the below code that copies numbers (that doesn't have a color) from a range (here D3 to D30) and pastes it into F column staring from row 1 and does some percentile calculation.
Problem is, I noticed that a stray number "5" appears in F column in the first row even though there is no such number in my range D3 - D30.
Sub TPNoRedpass50tablet()
Dim cel As Range
Dim Rng As Range
Dim arr As Variant
Dim i As Long
Application.ScreenUpdating = False
For Each cel In Sheets("TP").Range("TP!$D$3:$D$30")
If cel.Font.Color = 0 Then
If Rng Is Nothing Then
Set Rng = cel
Else
Set Rng = Union(cel, Rng)
End If
End If
Next cel
ReDim arr(Rng.count - 1)
If Not Rng Is Nothing Then
For Each cel In Rng
arr(i) = cel
i = i + 1
Next cel
Sheets("TP").Range("F1").Resize(UBound(arr) + 1).Value = Application.Transpose(arr)
Set Rng = Sheets("TP").Range("F1:I" & Sheets("TP").Cells(Rows.count, "F").End(xlUp).Row)
Sheets("WBR").Range("AH101").Formula = "=PERCENTILE.INC(" & Rng.Address(, , , True) & ",50%)*24"
Sheets("WBR").Range("AH101").Value = Sheets("WBR").Range("AH101").Value
End If
Application.ScreenUpdating = True
End Sub
Try this:
Sub TPNoRedpass50tablet()
Dim cel As Range
Dim Rng As Range
Dim arr As Variant
Dim i As Long
Application.ScreenUpdating = False
For Each cel In Sheets("TP").Range("TP!$D$3:$D$30")
If Rng Is Nothing Then
Set Rng = cel
If cel.Font.Color = 0 Then
Else
Set Rng = Union(cel, Rng)
End If
End If
Next cel
ReDim arr(Rng.count - 1)
If Not Rng Is Nothing Then
For Each cel In Rng
arr(i) = cel
i = i + 1
Next cel
Sheets("TP").Range("F1").Resize(UBound(arr) + 1).Value = Application.Transpose(arr)
Set Rng = Sheets("TP").Range("F1:I" & Sheets("TP").Cells(Rows.count, "F").End(xlUp).Row)
Sheets("WBR").Range("AH101").Formula = "=PERCENTILE.INC(" & Rng.Address(, , , True) & ",50%)*24"
Sheets("WBR").Range("AH101").Value = Sheets("WBR").Range("AH101").Value
End If
Application.ScreenUpdating = True
End Sub
The problem seems to be in the first for each loop. You have a union, which is carried out only the first time, when Rng is not set.