Filtering for the value in A1 - excel

I am trying to figure out a way to filter Column C for the value in A1, then put the formula in the first cell and copy down. I have the below code but I can't seem to get it to work. I have an example of the spreadsheet below the code.
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:="=RC[1]"
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
With .Columns(2)
.Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=RC[1]&""-R21"""
End With
End If
End With

I think the problem is that your formula is only being added to the first cell in your filtered range. That is because a discontiguous SpecialCells range such as yours, i.e., C7, C10,C12:C15, etc., will consist of multiple Areas. If that's the case, you need to loop through the Areas with a For/Next:
Dim FilteredArea as Range
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:="=RC[1]"
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
For Each FilteredArea in .Columns(2).Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Areas
FilteredArea.FormulaR1C1 = "=RC[1]&""-R21"""
Next FilteredArea
End If
End With
This is untested, but hopefully will give you an idea of how to work with Areas.

Set range("A1") as a variable
Sub Button2_Click()
Dim F As Range'declare F as a range
Set F = Range("A1")'set F as range("A1")
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:=F'Filter for F
If .Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
With .Columns(2)
.Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=RC[1]&""-R21"""
End With
End If
End With
End Sub
Here's another version, so you won't have to use Formulas.
Sub LoopThroughFilterd()
Dim rws As Long, rng As Range, Fltr As Range, c As Range
rws = Cells(Rows.Count, "A").End(xlUp).Row
Set rng = Range("C6:C" & rws)
Set Fltr = Range("A1")
Application.ScreenUpdating = 0
With ActiveSheet.Range("A5").CurrentRegion
.AutoFilter Field:=3, Criteria1:=Fltr
For Each c In rng.Cells
If c.EntireRow.Hidden = 0 Then
c.Offset(, -1) = c & "-R21"
End If
Next c
.AutoFilter
End With
End Sub
You can also Loop through the cells instead of filtering.
Sub LooPFor()
Dim rws As Long, rng As Range, Fltr As Range, c As Range
rws = Cells(Rows.Count, "A").End(xlUp).Row
Set rng = Range("C6:C" & rws)
Set Fltr = Range("A1")
For Each c In rng.Cells
If c = Fltr Then c.Offset(, -1) = c & "-R21"
Next c
End Sub

Related

Filter and delete the criteria that I have filtered from a different column

everyone. I am new in VBA language. From my situation,
1) I would like to filter "unfulfilled" from column H and delete it
2) I would like to filter "Y" from column Q and delete it
I have write some code to run it. When I press run at the 1st time I am able to filter and delete 1st requirement, but if I want to filter and delete 2nd requirement I need to press Run again. May I know how to run those requirement once. Attachment below are my code
Sub try2()
Dim Filterrng1 As Range, Filterrng2 As Range
Dim Delrng1 As Range, Delrng2 As Range
Dim FilterArr1
Dim FilterArr2
Application.ScreenUpdating = False
FilterArr1 = Array("Unfulfilled")
FilterArr2 = Array("Y")
Set Filterrng1 = Range("H1", Range("H" & Rows.Count).End(xlUp))
Set Filterrng2 = Range("Q1", Range("Q" & Rows.Count).End(xlUp))
Set Delrng1 = Filterrng1.Offset(1, 0)
Set Delrng2 = Filterrng2.Offset(1, 0)
Debug.Print LBound(FilterArr1)
Debug.Print LBound(FilterArr2)
For f = LBound(FilterArr1) To UBound(FilterArr1)
Filterrng1.AutoFilter Field:=1, Criteria1:="=" & FilterArr1(f)
If Filterrng1.SpecialCells(xlCellTypeVisible).Count > 1 Then
Delrng1.EntireRow.Delete
End If
For a = LBound(FilterArr2) To UBound(FilterArr2)
Filterrng2.AutoFilter Field:=1, Criteria1:="=" & FilterArr2(a)
If Filterrng2.SpecialCells(xlCellTypeVisible).Count > 1 Then
Delrng2.EntireRow.Delete
End If
Next
Next
Filterrng1.AutoFilter 'Remove Autofilter from range
Filterrng2.AutoFilter 'Remove Autofilter from range
End Sub
sub try3()
Dim rg As Range
Set rg = ActiveSheet.Range("H1").CurrentRegion 'Edit to your range
Dim Filterrng1 As Range, Filterrng2 As Range
Dim Delrng1 As Range, Delrng2 As Range
Dim FilterArr1
Dim FilterArr2
Set Filterrng1 = Range("H1", Range("H" & Rows.Count).End(xlUp))
Set Filterrng2 = Range("Q1", Range("Q" & Rows.Count).End(xlUp))
Set Delrng1 = Filterrng1.Offset(1, 0)
Set Delrng2 = Filterrng2.Offset(1, 0)
rg.AutoFilter Field:=1, Criteria1:="Unfulfilled"
If Filterrng1.SpecialCells(xlCellTypeVisible).Count > 1 Then
Delrng1.EntireRow.Delete
End If
rg.AutoFilter
rg.AutoFilter Field:=10, Criteria1:="Y"
If Filterrng2.SpecialCells(xlCellTypeVisible).Count > 1 Then
Delrng2.EntireRow.Delete
End If
end sub
Add other things like screenupdating, etc.

More efficient alternative to For Each

I am trying to get a faster and more efficient code than this one, as range will increase a lot over time, so I will need to substitute For Each.
The macro would look up the value "Monday" through each cell of a column and, if found, it would return the value "Substract" in the preceding cell in column A.
Sub ForEachTest()
Dim Rng As Range
Set Rng = Range("B3:B1000")
For Each cell In Rng
If cell.Value = "Monday" Then
cell.Offset(0, -1) = "Substract"
End If
Next cell
End Sub
Loop within VBA rather than on the worksheet:
Sub faster()
Dim arr()
arr = Range("A3:B1000")
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i, 2) = "Monday" Then arr(i, 1) = "Substract"
Next i
Range("A3:B1000") = arr
End Sub
EDIT#1:
This version addresses BigBen's concern that column B should not be overwritten so as to preserve any formulas in that column. Only column A is overwritten here:
Sub faster2()
Dim arr(), brr()
arr = Range("A3:A1000")
brr = Range("B3:B1000")
For i = LBound(brr, 1) To UBound(brr, 1)
If brr(i, 1) = "Monday" Then arr(i, 1) = "Substract"
Next i
Range("A3:A1000") = arr
End Sub
You can avoid the loop by filtering your data and working with the resulting visible set of data.
This will only modify the cells in Column A when Column B = Monday. All other cells remain as-is
Sub Shelter_In_Place()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
lr As Long
lr = ws.Range("B" & ws.Rows.Count).End(xlUp).Row
ws.Range("A1:B" & lr).AutoFilter Field:=2, Criteria1:="Monday"
ws.Range("A2:A" & lr).SpecialCells(xlCellTypeVisible).Value = "Subtract"
ws.AutoFilterMode = False
End Sub
Try using Evaluate
Sub Test()
With Range("A3:A" & Cells(Rows.Count, 2).End(xlUp).Row)
.Value = Evaluate("IF(" & .Offset(, 1).Address & "=""Monday"",""Substract"","""")")
End With
End Sub

Calculation of values based on the color of cells in Excel VBA

The code shows a simple average calculation based on the values in the defined cells. Those cells are highlighted in three colors. The aim is to take the values into the calcuation which cell color is e.g. green. I know the "if" command is needed, I just dont know where excatly to put it in:
Dim wb As Workbook, wq As Object
Dim ws As Worksheet, datdatum
Dim cell As Range, cell2 As Range, col As Long
ws.Range("H104:U104").Formula = "= Average(H34,H39,H68,H71,H83)"
I'll assume that entire rows are not green and that each column needs to be looked at independently.
Loop through each column from H to U. Loop through each cell in each column. Build a union of the cells that are green and average the union. Move on to the next column.
There is no point in building a formula for each column since any change would require rerunning the sub procedure. These will work on both manually set and conditional formatted cell colors.
.DisplayFormat does not work within a User Defined Function.
dim c as long, r as long, rng as range
with worksheets("sheet1")
for c =8 to 21
for r=2 to 103
if .cells(r, c).displayformat.interior.color = vbgreen then
if rng is nothing then
set rng = .cells(r, c)
else
set rng = union(rng, .cells(r, c))
end if
end if
next r
if not rng is nothing then _
.cells(104, c) = application.average(rng)
'alternate
'if not rng is nothing then _
'.cells(104, c).formula = "=average(" & rng.address(0,0) & ")"
next c
end with
Alternate,
dim c as long
with worksheets("sheet1")
if .autofiltermode then .autofiltermode = false
for c =8 to 21
with .range(.cells(1, c), .cells(103, c))
.AutoFilter Field:=1, Criteria1:=vbgreen, Operator:=xlFilterCellColor
.cells(104, c) = application.subtotal(101, .cells)
.AutoFilter
end with
next c
end with

Get a filtered range into an array

I am trying to get a filtered range into an array, on my test data the array fArr has the proper dim and fLR is the proper count of the filter range
But filRange is always only the header range NOT the filtered range
How to get filRange to be the filtered range?
Or to the point how to get fArr to be an array of the filter data?
Thanks
Sub arrFilterdRng()
Dim fArr As Variant
Dim rRange As Range, filRange As Range, myCell As Range
Dim fLR As Long, rCtr As Long
'Remove any filters
ActiveSheet.AutoFilterMode = False
'~~> Set your range
Set rRange = Sheets("Z").UsedRange
With rRange
'~~> Set your criteria and filter
.AutoFilter Field:=3, Criteria1:="*"
Set filRange = .SpecialCells(xlCellTypeVisible).EntireRow
fLR = .Resize(, 1).SpecialCells(xlCellTypeVisible).Count
Debug.Print fLR
ReDim fArr(1 To fLR, 1 To .Columns.Count)
Debug.Print UBound(fArr, 1), UBound(fArr, 2)
rCtr = 0
For Each myCell In filRange.Columns(1)
rCtr = rCtr + 1
For cCtr = 1 To .Columns.Count
fArr(rCtr, cCtr) = myCell.Offset(0, cCtr - 1).value
Next cCtr
Next myCell
End With
'Remove any filters
ActiveSheet.AutoFilterMode = False
End Sub
My data looks like this (all text)
My feeling is that the wildcard in your criteria is causing the trouble.
"*" only works for strings, so if your data are numbers (including dates) then they would be removed by the filter (ie they wouldn't be visible), so you would indeed only have the header in your range.
If you want numerical values, then one way of doing it would be to define a value, say:
.AutoFilter Field:=3, Criteria1:=">0"
or, if you want limits:
.AutoFilter Field:=3, Criteria1:=">0", Operator:=xlAnd, Criteria2:="<10"
If, on the other hand, you just want anything but blank cells, then the syntax should be:
.AutoFilter Field:=3, Criteria1:="<>"
You should also be aware that if the filtered range contains non-contiguous ranges, then each 'separate' range would be contained within the Areas collection. This means something like filRange.Rows.Count would only return the row count of the first area; and you can get real difficulties when you try to Offset and/or Resize the filtered range. It's also not possible to directly read non-contiguous ranges into an array using the .Value property.
I'm not sure your code is the most efficient way of handling your task, but keeping the same structure it could look like this:
Dim rRange As Range, filRange As Range
Dim myArea As Range, myRow As Range, myCell As Range
Dim fArr() As Variant
Dim r As Long
With ThisWorkbook.Worksheets("Z")
.AutoFilterMode = False
Set rRange = .UsedRange
End With
With rRange
.AutoFilter Field:=3, Criteria1:=">0"
Set filRange = .SpecialCells(xlCellTypeVisible)
End With
With filRange
r = -1 'start at -1 to remove heading row
For Each myArea In filRange.Areas
r = r + myArea.Rows.Count
Next
ReDim fArr(1 To r, 1 To .Columns.Count)
End With
r = 1
For Each myArea In filRange.Areas
For Each myRow In myArea.Rows
If myRow.Row <> 1 Then
For Each myCell In myRow.Cells
fArr(r, myCell.Column) = myCell.Value
Next
r = r + 1
End If
Next
Next
Perhaps your data has more complexity, but you can simply assign the values of a range to an array with:
var = rng.SpecialCells(xlCellTypeVisible).Value
Thus no need to loop over the data.
Here's a working example with this simple grid of data:
This code:
Option Explicit
Sub arrFilterdRng()
Dim ws As Worksheet '<-- your worksheet
Dim rng As Range '<-- your range to filter
Dim var As Variant '<-- will hold array of visible data
Dim lng1 As Long, lng2 As Long
' get sheet; remove filters
Set ws = ThisWorkbook.Worksheets("Sheet2")
ws.AutoFilterMode = False
' get range; apply filter
Set rng = ws.UsedRange
rng.AutoFilter Field:=1, Criteria1:="x"
' assign visible range to array
var = rng.SpecialCells(xlCellTypeVisible).Value
' test array
For lng1 = LBound(var, 1) To UBound(var, 1)
For lng2 = LBound(var, 2) To UBound(var, 2)
Debug.Print var(lng1, lng2)
Next lng2
Next lng1
End Sub
Results in this on the sheet:
And the output to the Immediate window for the content of var is:
a
b
c
x
2
3
x
5
6

VBA Excel - deleting rows at specific intervals

I am new to this forum, so bear with me.
I have a CSV-file that I need to apply some VBA-modules to in order to get the information I need.
In short, I have 3 macros that together to the following:
Create a new row every 20th row
Take the number from the cell above (column A) and fill the blank space in the new row with this number.
Sum the numbers in column H from the 20 rows before the new row to get a total score. This is done subsequently for as long as new rows appear (every 20th row).
Is it possible to get these three macros in a single macro? This would make it easier to hand down to others that may need to use these macros.
Current code:
' Step 1
Sub Insert20_v2()
Dim rng As Range
Set rng = Range("H2")
While rng.Value <> ""
rng.Offset(20).Resize(1).EntireRow.Insert
Set rng = rng.Offset(21)
Wend
End Sub
' Step 2
Sub FillBlanks()
Columns("A:A").Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.FormulaR1C1 = "=R[-1]C"
End Sub
' Step 3
Sub AutoSum()
Const SourceRange = "H"
Dim NumRange As Range, formulaCell As Range
Dim SumAddr As String
Dim c As Long
For Each NumRange In Columns(SourceRange).SpecialCells(xlConstants, xlNumbers).Areas
SumAddr = NumRange.Address(False, False)
Set formulaCell = NumRange.Offset(NumRange.Count, 0).Resize(1, 1)
formulaCell.Formula = "=SUM(" & SumAddr & ")"
'change formatting to your liking:
formulaCell.Font.Bold = True
formulaCell.Font.Color = RGB(255, 0, 0)
c = NumRange.Count
Next NumRange
End Sub
Thank you for any help.
Best,
Helge
You can create a single Sub calling all the other subs that you have created.
Example:
Sub DoAllTasks()
Insert20_v2
FillBlanks
AutoSum
End Sub
Then you just have to create a button and assign the DoAllTasks to it or run the macro directly.
HTH ;)
That Should'nt be that hard.
Public Sub main()
'deklaration
Dim rng As Range
Const SourceRange = "H"
Dim NumRange As Range, formulaCell As Range
Dim SumAddr As String
Dim c As Long
'Loop trough all Rows
Set rng = Range("H2")
While rng.Value <> ""
rng.Offset(20).Resize(1).EntireRow.Insert
Set rng = rng.Offset(21)
Wend
'Fill the Blank Rows in A
Columns("A:A").Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.FormulaR1C1 = "=R[-1]C"
For Each NumRange In Columns(SourceRange).SpecialCells(xlConstants, xlNumbers).Areas
SumAddr = NumRange.Address(False, False)
Set formulaCell = NumRange.Offset(NumRange.Count, 0).Resize(1, 1)
formulaCell.Formula = "=SUM(" & SumAddr & ")"
'change formatting to your liking:
formulaCell.Font.Bold = True
formulaCell.Font.Color = RGB(255, 0, 0)
c = NumRange.Count
Next NumRange
End Sub

Resources