loop through rows to copy range meeting criteria - vba

I have a workbook with a sheet (sheet2) containing 1600+ rows and 700+ columns.
Col A is name and Col B is counta of all columns from C to last col. It is always > 0.
The cell values of each column are like "29.11.17_124". Not all cells in these columns are filled. There are empty cells too. Each filled cell per col begins with the same date string.
I have a macro which asks for a date string. Then finds the col number where that string is. Suppose it is col 65. Then all rows from col A to col 65 are copied to sheet4. But in this sheet (sheet4), since the col B calculates new counta, I have to delete all rows where counta is < 1 as well.
Basically, I am copying 1600+ rows and then deleting 1000 rows (where counta is 0) in sheet4.
I want to modify my code so that only those rows whose counta is 1 and more are copied. The code to iterate through each row of sheet2 but also evaluate the new counta as derived from the col range.
Sub dcopyrange()
Dim rng1 As Range
Dim sh1 As Worksheet, sh2 As Worksheet
Dim fc As Integer
Dim lc As Integer
Dim valuee1 As Variant
Dim lRow As Long
Dim lRow2 As Long
Dim iCntr As Long
Sheet4.Cells.Clear
sheet2.Select
lRow2 = sheet2.Cells(Rows.Count, "A").End(xlUp).Row
Set sh1 = Sheets("Sheet2")
Set sh2 = Sheets("Sheet4")
valuee1 = InputBox("enter date dd-m-yy", "Report by department")
Set rng1 = sh1.UsedRange.Find(valuee1, , xlValues, xlPart)
If Not rng1 Is Nothing Then
MsgBox "Found in column " & rng1.Column
fc = 1
lc = (fc + rng1.Column) - 1
Range(Columns(fc), Columns(lc)).copy sh2.Range("A1")
Else
MsgBox "Not found", vbCritical
End If
ActiveWorkbook.Worksheets("Sheet4").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet4").Sort.SortFields.Add Key:=Range("b1:b2500" _
), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet4").Sort
.SetRange Range("A1:ZZ2500")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Sheet4.Activate
lRow = Sheet4.Cells(Rows.Count, "A").End(xlUp).Row
For iCntr = lRow To 1 Step -1
If Cells(iCntr, 2).Value = 0 Then Cells(iCntr, 2).EntireRow.Clear
Next iCntr
End Sub

Sub filtercopyrange()
Dim rng1 As Range
Dim sh1 As Worksheet, sh2 As Worksheet
Dim fcol As Integer
Dim lcol As Integer
Dim valuee1 As Variant
Dim lRow2 As Long
Dim lRow1 As Long
Dim iCntr As Long
Dim i As Integer
Dim ct As Variant
Sheet7.Cells.Clear
Sheet2.Select
Set sh1 = Sheets("Sheet2")
Set sh2 = Sheets("Sheet7")
valuee1 = InputBox("enter date dd-mm-yyyy", "Column Range")
Set rng1 = sh1.UsedRange.Find(valuee1, , xlValues, xlPart)
If Not rng1 Is Nothing Then
MsgBox "Found in column " & rng1.Column
fcol = 1
lcol = (fcol + rng1.Column) - 1
Else
MsgBox "Not found", vbCritical
End If
lRow2 = Sheet2.Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To lRow2
With sh1
ct = Application.WorksheetFunction.CountA(Range(Cells(i, 3), Cells(i, lcol)))
If ct > 0 Then
Sheet2.Range(Cells(i, 1), Cells(i, lcol)).Copy
Sheet7.Range("a" & Rows.Count).End(xlUp).Offset(1,0).PasteSpecial
Else
End If
End With
Next
Sheet7.Activate
lRow1 = Sheet7.Cells(Rows.Count, "A").End(xlUp).Row
Range("A1:bz" & lRow1).Sort key1:=Range("B1:B" & lRow1), _
order1:=xlDescending, Header:=xlNo
End Sub

Related

How to check if cells in different sheets are equal?

Scenario: -There are 2 sheets being compared. Range for Sheet1 is B2:B and for Sheet2 is C2:C.
Requirement:
Sheet1 B2 = Sheet2 C2
Sheet1 B3 = Sheet2 C3 and so on...
See my existing code below:
Sub MessageCode()
Dim FoundBlank1 As Range
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("Sheet2")
Dim MyRange As Range, MyCell As Range, MyRange2 As Range, MyCell2 As Range
Set MyRange = ws.Range("B2:B" & ws.Range("B" & ws.Rows.Count).End(xlUp).Row)
Set MyRange2 = ws2.Range("C2:C" & ws2.Range("C" & ws2.Rows.Count).End(xlUp).Row)
Set MyCell2 = MyRange2
For Each MyCell In MyRange
If MyCell.Value <> Worksheets("Sheet2").Range("C2").Value Then
MyCell.Copy
Worksheets("Sheet3").Select
Set FoundBlank1 = Range("A1:A1000").Find(What:="", lookat:=xlWhole)
FoundBlank1.Select
Selection.PasteSpecial xlPasteValues
ActiveCell.Offset(0, 1).Value = "Incorrect Value."
End If
Next MyCell
End Sub
I've added in some extra message box if the number of rows of sheet 1 and 2 are not the same.
Try this:
Sub Messagecode()
Dim ws As Worksheet
Dim ws2 As Worksheet
Dim lastrow1 As Integer
Dim lastrow2 As Integer
dim lastrow3 as integer
Dim i As Integer
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
ws1.Activate
lastrow1 = Cells(Rows.Count, 2).End(xlUp).Row
ws2.Activate
lastrow2 = Cells(Rows.Count, 3).End(xlUp).Row
If lastrow1 <> lastrow2 Then
MsgBox ("number of rows in Sheet1 is not equal to number of rows in Sheet2")
End If
For i = 2 To lastrow1
If ws1.Cells(i, 2) <> ws2.Cells(i, 3) Then
ws2.Cells(i, 3).Copy
Worksheets("Sheet3").Activate
lastrow3 = Cells(Rows.Count, 1).End(xlUp).Row
Cells(lastrow3, 1).Offset(1, 0).Activate
ActiveSheet.Paste
Cells(lastrow3, 1).Offset(1, 1) = "incorrect value"
End If
ws1.Activate
Next i
End Sub
You only need to set the last row for sheet1 and sheet3. run a loop from 2 to the lastrow and compare Sheet1.columnB with Sheet2.columnC if <> then copy the value in Sheet1 to Sheet3, offset 1 cell to the right and paste your text. You add +1 to the last row in Sheet3 so you don't keep writing over the same cell...
Dim i As Long
Dim lRow As Long
lRow = Sheet1.Cells(Rows.Count, "B").End(xlUp).Row
Dim lRow3 As Long
lRow3 = Sheet3.Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To lRow
If Sheet1.Cells(i, "B").Value <> Sheet2.Cells(i, "C").Value Then
Sheet3.Cells(lRow3, "A").Value = Sheet1.Cells(i, "B").Value
Sheet3.Cells(lRow3, "A").Offset(, 1).Value = "Incorrect Value."
End If
lRow3 = lRow3 + 1
Next i

Cut multiple columns if a certain cell in first row/header are the same

I am currently new to macro VBA and I have been trying to copy a column if the values of a specific rows are the same then paste it on another sheet until all columns are copied and pasted. The purpose of this is to consolidate team members of a team (the team is the value that im trying to look for). It only stops when the next cell to the right is already blank. And I will only find the team members' team on the first row of the sheet only. I placed a code that I found on the Internet and modified it but it only copies the last DATA team it finds. Thank you.
Dim ws As Worksheet
Dim aCell As Range, Rng As Range
Dim col As Long, lRow As Long
Dim colName As String
Set ws = ThisWorkbook.Sheets("Values")
With ws
Set aCell = .Range("A1:XFD1").Find(What:="DATA", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
aCell.EntireColumn.Cut
Sheets("Team").Columns("D:W").Insert Shift:=xlToRight
Else
MsgBox "Team not found"
End If
End With
You can try this.
Option Explicit
Sub CopyCols()
Dim ArrTeams() As String, Team As String
Dim TeamCounter As Long, LastCol As Long, FirstCol As Long, i As Long, LastColDest As Long
Dim SrcWs As Worksheet
Dim Wb As Workbook
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set Wb = ThisWorkbook
Set SrcWs = Wb.Sheets("Sheet1")
ReDim ArrTeams(1 To 1)
With Wb
With SrcWs
'find last column with team
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
TeamCounter = 1
FirstCol = 1 'or whatever your first column with teams is
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
If Not IsInArray(Team, ArrTeams) Then 'take only unique team names
ReDim Preserve ArrTeams(1 To TeamCounter)
ArrTeams(TeamCounter) = Team
TeamCounter = TeamCounter + 1
End If
End If
Next i
End With
'create new sheet for each team
For i = 1 To UBound(ArrTeams)
.Sheets.Add after:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
Next i
With SrcWs
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
With Wb.Sheets(Team)
'find last non empty column on destination sheet
LastColDest = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
.Cells(1, i).EntireColumn.Copy
Wb.Sheets(Team).Cells(1, LastColDest + 1).PasteSpecial
End If
Next i
End With
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
It should loop all columns on "Sheet1" starting in FirstCol and ending in LastCol, take unique team names from first row. Create new sheet for each unique team name. Copy entire column for each unique team name to coresponding sheet.
Just remember that it will allways add new sheets so if you want to run it multiple times then there should be check if sheet with specific name already exists.
EDIT
Add
Dim LastRow As Long, j As Long
And
Dim TargetWs As Worksheet
in declaration part at begining
Change loop for adding new sheets to
For i = 1 To UBound(ArrTeams)
.Sheets.Add after:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
.Sheets(ArrTeams(i)).Range("A2:A1000").FormulaR1C1 = _
"=SUM(RC[2]:RC[" & .Sheets(ArrTeams(i)).Columns.Count - 1 & "])"
Next i
at the end add
For i = LBound(ArrTeams) To UBound(ArrTeams)
Team = ArrTeams(i) 'team name and also sheet name
Set TargetWs = .Sheets(Team)
With TargetWs
.Calculate 'calculate SUM formula on each sheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row with data in column "A"
For j = LastRow To 2 Step -1 'assuming that in row 1 there is some header
If .Cells(j, "A") = 0 Then
.Cells(j, "A").EntireRow.Delete
End If
Next j
End With
Next i
This should do the trick as long as you don't have more than 1000 rows of data. If so you can adjust SUM formula to cover more rows or find last row with data on each "Team" sheet and adjust formula in loop.
Hi #Sphinx this is what I have so far. And I modified the code you have given and added something to it. The syntax that I do not have is on how to delete a row when a specific cell on column C has 0 value. And it should work on all ArrTeams(i) sheets only. Thank you for you help.
https://i.stack.imgur.com/M8NS8.png
Option Explicit
Sub CopyCols()
Dim ArrTeams() As String, Team As String
Dim TeamCounter As Long, LastCol As Long, FirstCol As Long, i As Long, LastColDest As Long
Dim SrcWs As Worksheet
Dim Wb As Workbook
Dim LastRowColumnD As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set Wb = ThisWorkbook
Set SrcWs = Wb.Sheets("Values")
ReDim ArrTeams(1 To 1)
With Wb
With SrcWs
'find last column with team
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
TeamCounter = 1
FirstCol = 1 'or whatever your first column with teams is
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
If Not IsInArray(Team, ArrTeams) Then 'take only unique team names
ReDim Preserve ArrTeams(1 To TeamCounter)
ArrTeams(TeamCounter) = Team
TeamCounter = TeamCounter + 1
End If
End If
Next i
End With
'create new sheet for each team
For i = 1 To UBound(ArrTeams)
.Sheets.Add After:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
Sheets("Values").Columns("A:C").Copy
ActiveSheet.Paste Destination:=Worksheets(ArrTeams(i)).Range("A1:C1")
Range("A1").Value = " "
Range("B1").Value = " "
Range("C1").Value = " "
Range("A2").Value = "Team:"
Range("B2").Value = ArrTeams(i)
Range("C2").Value = " "
Range("B2").HorizontalAlignment = xlCenter
Range("B2").VerticalAlignment = xlCenter
Range("A2").HorizontalAlignment = xlCenter
Range("A2").VerticalAlignment = xlCenter
LastRowColumnD = Cells(Rows.Count, 1).End(xlUp).Row
Range("C4:C" & LastRowColumnD).Formula = "=sum(D4:XFD4)"
Next i
With SrcWs
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
With Wb.Sheets(Team)
'find last non empty column on destination sheet
LastColDest = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
.Cells(1, i).EntireColumn.Copy
Wb.Sheets(Team).Cells(1, LastColDest + 1).PasteSpecial
End If
Next i
End With
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function

Search a each value from a column of sheet in another sheet's column and if find then paste entire row in output

I'm new to this so please help me. I have a workbook with below three sheets-
Sheet1- Has 3 cloumns- A,B,C
Sheet2- Has One Column- A
**Ouput
If Value in a cell of Sheet1- Column B matches with value in any cell of Sheet2 Column A then copy that entire row and paste to next available blank row (starts from column A) of output sheet.
column B of sheet 2 can have duplicate cells and all the matched cells should go to next available row of output sheet.
**Sheet 1** **Sheet 2** **Output**
A B C A 3 Glen 28
1 Jen 26 Glen 1 Jen 26
2 Ben 24 Jen 4 Jen 18
3 Glen 28
4 Jen 18
I tried below. Not sure how good it is-
Sub Test()
Set objwork1 = ActiveWorkbook ' Workbooks("Search WR")
Set obj1 = objwork1.Worksheets("Header")
Set obj2 = objwork1.Worksheets("XML1")
Set obj3 = objwork1.Worksheets("VC")
Set obj4 = objwork1.Worksheets("Output")
i = 2
j = 2
Do Until (obj3.Cells(j, 1)) = ""
If obj2.Cells(i, 2) = obj3.Cells(j, 1) Then
Set sourceColumn = obj2.Rows(i)
Set targetColumn = obj4.Rows(j)
sourceColumn.Copy Destination:=targetColumn
Else
i = i + 1
End If
j = j + 1
Loop
End Sub
Tried below as well-
Sub Check()
Set objwork1 = ActiveWorkbook ' Workbooks("Search WR")
Set obj1 = objwork1.Worksheets("Header")
Set obj2 = objwork1.Worksheets("XML1")
Set obj3 = objwork1.Worksheets("VC")
Set obj4 = objwork1.Worksheets("Output")
Dim LR As Long, i As Long, j As Long
j = 2
LR = Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LR
For j = 2 To LR
obj3.Select
If obj3.Range("A" & i).value = obj2.Range("B" & j).value Then
Rows(j).Select
Selection.Copy
obj4.Select
obj4.Range("A1").End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
obj3.Select
End If
Next j
Next i
End Sub
Another approach
Copy all rows from Sheet1 to Output
Sort Output by custom list order (Sheet2)
Remove all rows in Output not in list (beginning in the last row)
So …
Option Explicit
Public Sub CopyListedRowsAndSortByListOrder()
Dim wsSrc As Worksheet
Set wsSrc = Worksheets("Sheet1")
Dim lRowSrc As Long
lRowSrc = wsSrc.Cells(wsSrc.Rows.Count, "A").End(xlUp).Row
Dim wsList As Worksheet
Set wsList = Worksheets("Sheet2")
Dim lRowList As Long
lRowList = wsList.Cells(wsList.Rows.Count, "A").End(xlUp).Row
Dim wsDest As Worksheet
Set wsDest = Worksheets("Output")
'Copy all rows
wsSrc.Range("A1:C" & lRowSrc).Copy wsDest.Range("A1")
Dim lRowDest As Long
lRowDest = wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Row
'sort Output column B by list in Sheet2
With wsDest.Sort
.SortFields.Add Key:=wsDest.Range("B2:B" & lRowDest), _
SortOn:=xlSortOnValues, Order:=xlAscending, CustomOrder:= _
Join(WorksheetFunction.Transpose(wsList.Range("A2:A" & lRowList).Value), ","), DataOption:=xlSortNormal
.SetRange Range("A1:C" & lRowDest)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'remove all rows not in list (backwards)
Dim i As Long
For i = lRowDest To 2 Step -1
If Not IsError(Application.Match(wsDest.Cells(i, "B"), wsList.Range("A2:A" & lRowList))) Then Exit For
Next i
wsDest.Range(i + 1 & ":" & lRowDest).Delete xlShiftUp
End Sub
Something like (assumes you are copying from first sheet. That wasn't clear).
Option Explicit
Sub test()
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set wb = ThisWorkbook
Set ws1 = wb.Worksheets("Sheet1")
Set ws2 = wb.Worksheets("Sheet2")
Set ws3 = wb.Worksheets("Output")
Dim currCell As Range, unionRng As Range
'Sheet1 column B matches sheet2 column A
With ws1
For Each currCell In Intersect(.Range("B:B"), .UsedRange)
If FoundInColumn(ws2, currCell, 1) Then
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, currCell.EntireRow)
Else
Set unionRng = currCell.EntireRow
End If
End If
Next currCell
End With
If Not unionRng Is Nothing Then unionRng.Copy ws3.Range("A" & IIf(GetLastRow(ws3, 1) = 1, 1, GetLastRow(ws3, 1)))
End Sub
Public Function FoundInColumn(ByVal ws As Worksheet, ByVal findString As String, ByVal columnNo As Long) As Boolean
Dim foundCell As Range
Set foundCell = ws.Columns(columnNo).Find(What:=findString, After:=ws.Cells(1, columnNo), LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not foundCell Is Nothing Then FoundInColumn = True
End Function
Public Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function
If it is everything from sheet2 that matches to copy then:
Option Explicit
Sub test2()
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set wb = ThisWorkbook
Set ws1 = wb.Worksheets("Sheet1")
Set ws2 = wb.Worksheets("Sheet2")
Set ws3 = wb.Worksheets("Output")
Dim currCell As Range, unionRng As Range
Dim dict As Dictionary 'tools > references > ms scripting runtime
Set dict = New Dictionary
'Sheet1 column B matches sheet2 column A
With ws1
For Each currCell In Intersect(.Range("B:B"), .UsedRange)
If Not dict.Exists(currCell.Value) And Not IsEmpty(currCell) Then
dict.Add currCell.Value, currCell.Value
Dim tempRng As Range
Set tempRng = GatherRanges(currCell.Value, Intersect(ws2.Range("A:A"), ws2.UsedRange))
If Not tempRng Is Nothing Then
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, tempRng)
Else
Set unionRng = tempRng
End If
End If
End If
Next currCell
End With
If Not unionRng Is Nothing Then unionRng.EntireRow.Copy ws3.Range("A" & IIf(GetLastRow2(ws3, 1) = 1, 1, GetLastRow2(ws3, 1)))
End Sub
Public Function GatherRanges(ByVal findString As String, ByVal searchRng As Range) As Range
Dim foundCell As Range
Dim gatheredRange As Range
With searchRng
Set foundCell = searchRng.Find(findString)
Set gatheredRange = foundCell
Dim currMatch As Long
For currMatch = 1 To WorksheetFunction.CountIf(.Cells, findString)
Set foundCell = .Find(What:=findString, After:=foundCell, _
LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not gatheredRange Is Nothing Then
Set gatheredRange = Union(gatheredRange, foundCell)
Else
Set gatheredRange = foundCell
End If
Next currMatch
End With
Set GatherRanges = gatheredRange
End Function
Public Function GetLastRow2(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow2 = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function
you could try this
Sub Test()
Dim filts As Variant
With Worksheets("Sheet2")
filts = Application.Transpose(.Range("A2", .Cells(.Rows.Count, 1).End(xlUp)).Value)
End With
With Worksheets("Sheet1").Range("A1").CurrentRegion
.AutoFilter Field:=2, Criteria1:=filts, Operator:=xlFilterValues
If Application.WorksheetFunction.Subtotal(103, .Columns(1)) > 1 Then .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0).SpecialCells(xlCellTypeVisible).Copy Worksheets("Output").Range("A1")
.Parent.AutoFilterMode = False
End With
End Sub

Name Range and then autofilter

I have two sheets. Sheet1 (PasteHere) has a long list of values in col B. For example:
100000
100100
100800
100801
200501
etc
Sheet2 (Landing) has a list I need to filter by. For example:
100000
100801
The end result is that I would like the values in sheet 1 to be filtered by the values in sheet 2. I am thinking I could name the range in sheet 2 and then filter by it, but it is not working. Here is the code I have so far. I am naming the range "CustList"
Sub FilterList()
Sheets("Landing").Select
Dim LastRow1 As Long
LastRow1 = Range("B" & Rows.Count).End(xlUp).Row
Range("B15:B" & LastRow1).Select
ActiveWorkbook.Names.Add Name:="CustList", RefersToR1C1:= _
"=Landing!R15C2:R[" & LastRow1 & "]C2"
Range("E16").Select
Dim vCrit As Variant
Dim rngCrit As Range
Set rngOrders = Sheets("PasteHere").Range("$A$1").CurrentRegion
Set rngCrit = Sheets("Landing").Range("CustList")
vCrit = rngCrit.Value
Sheets("PasteHere").Select
rngOrders.AutoFilter _
Field:=2, _
Criteria1:=Application.Transpose(vCrit), _
Operator:=xlFilterValues
End Sub
Use the below code.
Dim LastRow1, LastRow2, iLoop
Sheets("Landing").Select
LastRow1 = ActiveSheet.Range("B" & Rows.Count).End(xlUp).Row
ReDim xarr(LastRow1 - 14)
For iLoop = 1 To LastRow1 - 14
xarr(iLoop) = ActiveSheet.Range("B" & iLoop)
Next
Sheets("PasteHere").Select
LastRow2 = ActiveSheet.Range("B" & Rows.Count).End(xlUp).Row
ActiveSheet.Range("B1").Select
Selection.AutoFilter
ActiveSheet.Range("$B$1:$B$" & LastRow2).AutoFilter Field:=1, Criteria1:=xarr, Operator:=xlFilterValues
Try this code:
Option Explicit
Sub FilterRange()
'declaration of variables
Dim filterBy As Variant, toFilter As Variant, lastRow1 As Long, lastRow2 As Long, i As Long, j As Long, k As Long, _
filtered As Variant, ws1 As Worksheet, ws2 As Worksheet, flag As Boolean
k = 1
flag = True
'set references to worksheets, it's good to use them when you deal with more than one worksheet
'REMEMBER: use your own sheet name and change ranges I used (I used A column)
Set ws1 = Worksheets("Arkusz1")
Set ws2 = Worksheets("Arkusz2")
'set the ranges (storethem as arrays): to filter and one to filter by
lastRow1 = ws1.Cells(Rows.Count, 1).End(xlUp).Row
toFilter = ws1.Range("A1:A" & lastRow1).Value2
'clear range, we will write here filtered values
ws1.Range("A1:A" & lastRow1).Clear
lastRow2 = ws2.Cells(Rows.Count, 1).End(xlUp).Row
filterBy = ws2.Range("A1:A" & lastRow1).Value2
'here you loop thorugh arrays, checking if one element is in the other array
'if it isn't, write this value to cell on ws1
For i = 1 To lastRow1
flag = True
For j = 1 To lastRow2
If toFilter(i, 1) = filterBy(j, 1) Then
flag = False
Exit For
End If
Next
If flag Then
ws1.Cells(k, 1).Value = toFilter(i, 1)
k = k + 1
End If
Next
End Sub

VBA find a range of same values in a column and calculate average

I want to find a range of same values in column A , and then calculate it average , can anyone help me ? below the code :
https://i.stack.imgur.com/bU1hW.png
Sub test()
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow
Columns("A:A").Select
Set cell = sELECTION.Find(What:="i", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If cell Is Nothing Then
'do it something
Else
'do it another thing
End If
End Sub
Thanks !
Solution 1
Try this
Sub test()
Dim sht As Worksheet
Dim inputLR As Long, outputLR As Long
Dim cel As Range, aRng As Range, bRng As Range
Set sht = ThisWorkbook.Worksheets("Sheet1") 'your data sheet
With sht
inputLR = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row in column A
outputLR = .Cells(.Rows.Count, "D").End(xlUp).Row 'last row in column D
Set aRng = .Range(.Cells(2, 1), .Cells(inputLR, 1)) 'data range in column A
Set bRng = .Range(.Cells(2, 2), .Cells(inputLR, 2)) 'data range in column B
For Each cel In .Range(.Cells(2, 4), .Cells(outputLR, 4)) 'loop through each cell in Column D
cel.Offset(0, 1) = Application.WorksheetFunction.AverageIf(aRng, cel, bRng) 'calculate average
Next cel
End With
End Sub
See image for reference.
Solution 2
Another easier approach will be to use formula. Enter the following formula in Cell E2
=AVERAGEIF($A$2:$A$11,D2,$B$2:$B$11)
Drag/Copy down as required. Change range as per your data.
For details on AVERAGEIF see this.
EDIT : 1
Sub test()
Dim sht As Worksheet
Dim inputLR As Long, outputLR As Long
Dim cel As Range, aRng As Range, bRng As Range
Dim dict As Object, c As Variant, i As Long
Set dict = CreateObject("Scripting.Dictionary")
Set sht = ThisWorkbook.Worksheets("Sheet1") 'your data sheet
With sht
inputLR = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row in column A
Set aRng = .Range(.Cells(2, 1), .Cells(inputLR, 1)) 'data range in column A
Set bRng = .Range(.Cells(2, 2), .Cells(inputLR, 2)) 'data range in column B
c = aRng
For i = 1 To UBound(c, 1)
dict(c(i, 1)) = 1
Next i
.Range("D2").Resize(dict.Count) = Application.Transpose(dict.keys) 'display uniques from column A
outputLR = .Cells(.Rows.Count, "D").End(xlUp).Row 'last row in column D
For Each cel In .Range(.Cells(2, 4), .Cells(outputLR, 4)) 'loop through each cell in Column D
cel.Offset(0, 1) = Application.WorksheetFunction.AverageIf(aRng, cel, bRng) 'calculate average
Next cel
End With
End Sub
EDIT : 2 To get Min, instead of
For Each cel In .Range(.Cells(2, 4), .Cells(outputLR, 4)) 'loop through each cell in Column D
cel.Offset(0, 1) = Application.WorksheetFunction.AverageIf(aRng, cel, bRng) 'calculate average
Next cel
use
For Each cel In .Range(.Cells(2, 4), .Cells(outputLR, 4)) 'loop through each cell in Column D
cel.Offset(0, 1).FormulaArray = "=MIN(IF(" & aRng.Address & "=" & cel.Value & "," & bRng.Address & "))"
Next cel
.Range(.Cells(2, 4), .Cells(outputLR, 4)).Offset(0, 1).Value = .Range(.Cells(2, 4), .Cells(outputLR, 4)).Offset(0, 1).Value
Use WorksheetFunction.AverageIf function, see code below :
Sub test()
Dim sht As Worksheet
Dim LastRow As Long
Dim Rng As Range
Dim Avg1 As Double, Avg2 As Double
Set sht = ThisWorkbook.Worksheets("Sheet1")
With sht
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set Rng = .Range("A1:A" & LastRow)
' average of values in column B of all cells in column A = 1
Avg1 = WorksheetFunction.AverageIf(Rng, "1", .Range("B1:B" & LastRow))
' average of values in column B of all cells in column A = 2
Avg2 = WorksheetFunction.AverageIf(Rng, "2", .Range("B1:B" & LastRow))
End With
End Sub
This is using a variant array method. Try this.
Sub test()
Dim sht As Worksheet
Dim LastRow As Long
Dim vDB, vR(), rngDB, vResult()
Dim r As Integer, n As Long, j As Long, i As Integer
Set sht = ThisWorkbook.Worksheets("Sheet1")
With sht
LastRow = .Cells(Rows.Count, "A").End(xlUp).Row
rngDB = .Range("a1", "b" & LastRow)
vDB = .Range("d2", .Range("d" & Rows.Count).End(xlUp))
r = UBound(vDB, 1)
ReDim vResult(1 To r)
For i = 1 To r
n = 0
For j = 1 To LastRow
If vDB(i, 1) = rngDB(j, 1) Then
n = n + 1
ReDim Preserve vR(1 To n)
vR(n) = rngDB(j, 2)
End If
Next j
vResult(i) = WorksheetFunction.Average(vR)
Next i
.Range("e2").Resize(r) = WorksheetFunction.Transpose(vResult)
End With
End Sub
To use the .Find Function
Find the values in column A excluding duplicates
Use the unique values on the Find Function
When the value is found, sum the value in column B and on a counter
Divide the sum value by the counter to obtain the average value
Dim ws As Worksheet
Dim rng As Range, rngloop As Range, cellFound As Range, c As Range
Set ws = ThisWorkbook.Sheets(1)
lastrow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range(ws.Cells(2, 1), ws.Cells(lastrow, 1))
For i = 2 To lastrow
Set c = ws.Cells(i, 1)
Set rngloop = ws.Range(ws.Cells(2, 1), ws.Cells(i, 1))
x = Application.WorksheetFunction.CountIf(rngloop, c)
If x = 1 Then
'Debug.Print c 'Values in column A without duplicates
'Work with the values found
With rng
Set cellFound = .Find(what:=c, LookIn:=xlValues, MatchCase:=False)
If Not cellFound Is Nothing Then
FirstAddress = cellFound.Address
Do
SumValues = ws.Cells(cellFound.Row, 2) + SumValues
k = k + 1
Set cellFound = .FindNext(cellFound)
Loop While Not cellFound Is Nothing And cellFound.Address <> FirstAddress
AverageValues = SumValues / k
Debug.Print "Value: " & c & " Average: " & AverageValues
End If
End With
End If
k = 0
SumValues = 0
Next i
Note that the use of .Find is slower than CreateObject("Scripting.Dictionary"), so for large Spreadsheets the code of #Mrig is optimized
Please try this code:
Sub test()
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow
If Application.WorksheetFunction.CountIf(sht.Range("A1:A" & LastRow), sht.Range("A" & i)) > 1 Then
'if found more than one value
'do it another thing
sht.Range("B" & i) = Application.WorksheetFunction.SumIf(sht.Range("A1:A" & LastRow), _
sht.Range("A" & i)) / Application.WorksheetFunction.CountIf(sht.Range("A1:A" & LastRow), sht.Range("A" & i))
Else
'do it another thing
End If
Next i
End Sub
Hope this help.