Excel 2016 Macro to Copy Range Excluding Duplicates - excel

I have put together the following code to copy a range of IDs. The range contains many duplicates and I just want to paste one occurrence of each ID.
I keep getting a syntax error and I can't see what I am doing wrong. Can anyone point out the issue?
Thanks
Sub CopyIDs()
With ThisWorkbook.Sheets("DataTable").Range("A1", .Range("A1").End(xlDown)).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=ThisWorkbook.Sheets("Analysis").Range("A8"), Unique:=True
ThisWorkbook.Sheets("Analysis").Range("A8").Delete Shift:=xlShiftUp
End With
End Sub

You use "With" and "End With" in an incorrect way.
If you want to skip to specify the "Date Table" sheets twice, you may refer below code
With ThisWorkbook.Sheets("DataTable")
.Range("A1", .Range("A1").End(xlDown)).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=ThisWorkbook.Sheets("Analysis").Range("A8"), Unique:=True
End With

Advanced Filter vs Dictionary
The following contains 2 Advanced Filter solutions and 2 Dictionary solutions the latter using the getUniqueColumn function.
The Code
Option Explicit
' Stand-Alone
Sub copyIDsQF()
' To prevent 'Run-time error '1004':
' The extract range has a missing or invalid field name.':
ThisWorkbook.Worksheets("Analysis").Range("A8").ClearContents
With ThisWorkbook.Worksheets("DataTable")
.Range("A1", .Range("A1").End(xlDown)).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=ThisWorkbook.Worksheets("Analysis").Range("A8"), _
Unique:=True
End With
ThisWorkbook.Worksheets("Analysis").Range("A8").Delete Shift:=xlShiftUp
End Sub
' Stand-Alone
Sub CopyIDsCool()
With ThisWorkbook
' Define Source Column Range.
Dim SourceRange As Range
With .Worksheets("DataTable")
' If you ars sure that the range is contiguous:
Set SourceRange = .Range("A1", .Range("A1").End(xlDown))
' If not, rather use the following:
'Set SourceRange = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp))
' but then you could have the empty string as a unique value.
End With
' Define Target First Cell Range.
Dim TargetFirstCell As Range
Set TargetFirstCell = .Worksheets("Analysis").Range("A8")
End With
Application.ScreenUpdating = False
' To prevent 'Run-time error '1004':
' The extract range has a missing or invalid field name.':
TargetFirstCell.ClearContents
' Copy unique values from Source Column Range to Target Column Range.
SourceRange.AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=TargetFirstCell, _
Unique:=True
' Delete Target First Cell Range i.e. remove copied header.
TargetFirstCell.Delete Shift:=xlShiftUp
Application.ScreenUpdating = True
End Sub
' Uses the getUniqueColumn Function.
Sub CopyIDsMagicNumbers()
' Write unique values from Source Column to Data Array ('Data').
Dim Data As Variant
Data = getUniqueColumn(ThisWorkbook.Worksheets("DataTable"), "A", 2)
' Validate Data Array.
If IsEmpty(Data) Then
GoTo ProcExit
End If
' Write values from Data Array to Target Range.
With ThisWorkbook.Worksheets("Analysis").Range("A8")
' Clear contents in Target Column from Target First Cell to bottom.
.Resize(.Worksheet.Rows.Count - .Row + 1).ClearContents
' Write values from Data Array to Target Range.
.Resize(UBound(Data, 1)).Value = Data
End With
ProcExit:
End Sub
' Uses the getUniqueColumn Function.
Sub CopyIDs()
' Source
Const srcName As String = "DataTable"
Const UniCol As Variant = "A"
Const FirstRow As Long = 2
' Target
Const tgtName As String = "Analysis"
Const tgtFirstCell As String = "A8"
' Workbook
Dim wb As Workbook
Set wb = ThisWorkbook
' Write unique values from Source Column to Data Array ('Data').
Dim Data As Variant
Data = getUniqueColumn(wb.Worksheets(srcName), UniCol, FirstRow)
' Validate Data Array.
If IsEmpty(Data) Then
GoTo ProcExit
End If
' Write values from Data Array to Target Range.
With wb.Worksheets(tgtName).Range(tgtFirstCell)
' Clear contents in Target Column from Target First Cell to bottom.
.Resize(.Worksheet.Rows.Count - .Row + 1).ClearContents
' Write values from Data Array to Target Range.
.Resize(UBound(Data, 1)).Value = Data
End With
ProcExit:
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the unique values of a column range
' in a 2D one-based one-column array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getUniqueColumn(Sheet As Worksheet, _
Optional ByVal ColumnIndex As Variant = 1, _
Optional ByVal FirstRow As Long = 1) _
As Variant
' Validate worksheet.
If Sheet Is Nothing Then
GoTo ProcExit ' Worksheet is 'Nothing'.
End If
' Define Processing Range ('rng').
Dim rng As Range
Set rng = Sheet.Columns(ColumnIndex) _
.Resize(Sheet.Rows.Count - FirstRow + 1) _
.Offset(FirstRow - 1)
' Define Last Non-Empty Cell ('cel') in Processing Range.
Dim cel As Range
Set cel = rng.Find(What:="*", _
LookIn:=xlFormulas, _
SearchDirection:=xlPrevious)
' Validate Last Non-Empty Cell.
If cel Is Nothing Then
GoTo ProcExit ' Processing Range is empty.
End If
' Define Non-Empty Column Range ('rng').
Set rng = rng.Resize(cel.Row - FirstRow + 1)
' Write values from Non-Empty Column Range to Data Array ('Data').
Dim Data As Variant
If rng.Rows.Count > 1 Then
Data = rng.Value
Else
ReDim Data(1, 1)
Data(1, 1) = rng.Value
End If
' Write values from Data Array to Unique Dictionary ('dict').
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim Key As Variant
Dim i As Long
For i = 1 To UBound(Data)
Key = Data(i, 1)
If Not IsError(Key) And Not IsEmpty(Key) Then
dict(Key) = Empty
End If
Next i
' Validate Unique Dictionary.
If dict.Count = 0 Then
GoTo ProcExit ' There are only error and/or empty values in Data Array.
End If
' Write values from Unique Dictionary to Data Array ('Data').
ReDim Data(1 To dict.Count, 1 To 1)
i = 0
For Each Key In dict.Keys
i = i + 1
Data(i, 1) = Key
Next Key
' Write Data Array to result.
getUniqueColumn = Data
ProcExit:
End Function

Related

How to use a Named Range/Array to AutoFilter a Table?

I am using the below code to set an array to the values in a Named Range (containing account numbers) and then use that array as the criteria to AutoFilter a table (Table1).
Sub FilterRangeCriteria()
Dim vCrit As Variant
Dim rngCrit As Range
Set rngCrit = wsL.Range("CritList")
vCrit = rngCrit.Value
wsO.ListObjects("Table1").Range.AutoFilter _
Field:=8, _
Criteria1:=vCrit, _
Operator:=xlFilterValues
End Sub
I can see that the array contains all of the values from the named range however the table that I'm trying to filter will eliminate all rows below the header and not show any rows with the criteria from the named range.
This will work if CritList is a single column or row. Otherwise, you'll have to create a 1D array from the values.
Sub FilterRangeCriteria()
Dim vCrit As Variant
Dim rngCrit As Range
Set rngCrit = wsL.Range("CritList")
vCrit = WorksheetFunction.Transpose(WorksheetFunction.Unique(rngCrit))
wsO.ListObjects("Table1").Range.AutoFilter _
Field:=8, _
Criteria1:=vCrit, _
Operator:=xlFilterValues
End Sub
EDIT
For the filter to work properly, the numeric values need to be converted to strings.
Sub FilterRangeCriteria()
Dim vCrit As Variant
Dim rngCrit As Range
Set rngCrit = wsL.Range("CritList")
vCrit = WorksheetFunction.Transpose(WorksheetFunction.Unique(rngCrit))
Rem Numeric filter values need to be converted to strings
Dim n As Long
For n = LBound(vCrit) To UBound(vCrit)
vCrit(n) = CStr(vCrit(n))
Next
wsO.Range("A11").CurrentRegion.AutoFilter Field:=8, Criteria1:=vCrit, Operator:=xlFilterValues
End Sub
Filter Excel Table Column on Values of a Named Range
Sub FilterRangeCriteria()
' Source - read criteria list
' 'wsL' is the code name of a worksheet containing this code
Const sRangeName As String = "CritList"
' Destination - filter a table
' 'wsO' is the code name of a worksheet containing this code
Const dtblName As String = "Table1"
Const dlcName As String = "Ledger Account"
' Keep in mind that this would fail on 'UBound(cData, 1)'
' if there was only one cell in the named range.
Dim cData As Variant: cData = wsL.Range(sRangeName).Value
' "AutoFilter" 'likes' strings and the array needs to be 1D,
' hence write the values from the 2D one-based one-column criteria array,
' converted to strings, to a 1D one-based string array ('sArr').
Dim sArr() As String: ReDim sArr(1 To UBound(cData, 1))
Dim r As Long
For r = 1 To UBound(cData, 1)
sArr(r) = CStr(cData(r, 1))
Next r
' Reference the destination table.
Dim dtbl As ListObject: Set dtbl = wsO.ListObjects(dtblName)
Application.ScreenUpdating = False
' Remove any filters.
If dtbl.ShowAutoFilter Then
If dtbl.AutoFilter.FilterMode Then dtbl.AutoFilter.ShowAllData
Else
dtbl.ShowAutoFilter = True
End If
' Reference the destination table criteria column.
Dim dlc As ListColumn: Set dlc = dtbl.ListColumns(dlcName)
' Apply the filter.
dtbl.Range.AutoFilter dlc.Index, sArr, xlFilterValues
Application.ScreenUpdating = True
' Inform.
MsgBox "Table filtered.", vbInformation
End Sub

Select first empty cell in column AND works for empty column [duplicate]

This question already has answers here:
Find last used cell in Excel VBA
(14 answers)
Closed 1 year ago.
I need to find the first blank cell in a column. The solution for this is easy assuming there are 2 or more filled cells in the column.
Range("A1").End(xlDown).Offset(1, 0).Select
This stops working if the only populated cell is A1 or if A1 is blank.
In these cases it will select the last cell in the workbook.
Is there any work around that will always select the first blank cell in the column even if that cell happens to be A1 or A2?
Here is a solution that tests if the cell we find is empty and if A1 is empty:
Dim Rng As Range
Set Rng = Range("A1").End(xlDown)
If Rng.Value = "" Then
If Range("A1").Value = "" Then
Range("A1").Select
Else
Range("A2").Select
End If
Else
Rng.Offset(1, 0).Select
End If
In the comment you write that you don't like the order of the code, here is another example:
If Range("A1").Value = "" Then
Range("A1").Select
ElseIf Range("A2").Value = "" Then
Range("A2").Select
Else
Range("A1").End(xlDown).Offset(1, 0).Select
End If
And here is another example that avoids the use of End() and Offset():
Dim Cnt As Long
Cnt = ActiveSheet.UsedRange.Rows.Count
If Cnt = 1 And Range("A1").Value = "" Then Cnt = 0
Range("A" & Cnt + 1).Select
If you add a header row, then this example works:
Range("A" & ActiveSheet.UsedRange.Rows.Count + 1).Select
I always include a header row in all sheets with tabular data, to limit special cases - it's also more user friendly.
Find First Empty Cell by Looping
Empty
Except looping through cells, there are various more or less reliable ways to do it.
If there are hidden rows or columns, many of them will not work.
Even worse, if the worksheet is filtered, probably most of them will not work.
The Basic Loop
If you loop through the cells and test each one of them, you will surely get the correct result.
Function RefFirstEmptyCellInColumnBasic( _
ByVal FirstCell As Range) _
As Range
' Validate the given range ('FirstCell').
If FirstCell Is Nothing Then Exit Function
' Create a reference to the Column Range ('crg').
With FirstCell.Cells(1)
Dim crg As Range: Set crg = .Resize(.Worksheet.Rows.Count - .Row + 1)
End With
' Loop.
Dim cCell As Range
' Loop through the cells of the Column Range...
For Each cCell In crg.Cells
' ... until an empty cell is found.
If IsEmpty(cCell) Then
' Create a reference to the current cell.
Set RefFirstEmptyCellInColumnBasic = cCell
Exit Function
End If
Next cCell
End Function
The issue is that it may take a long time. It will 'behave' for a few thousand rows but e.g. if the first empty cell is the last cell in the column, the previous code takes 'forever' (5s) on my machine.
Loop in Memory (Array)
To remedy this, you can introduce an array into the previous code which will reduce the execution time ten times (0.5s). (Note that it will roughly take 0.05s each time for just writing the values to the array.)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the top-most empty cell
' in the one-column range from the first cell of a range
' ('FirstCell') through the last cell in its column.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefFirstEmptyCellInColumn( _
ByVal FirstCell As Range) _
As Range
' Validate the given range ('FirstCell').
If FirstCell Is Nothing Then Exit Function
' Create a reference to the Column Range ('crg').
With FirstCell.Cells(1)
Dim crg As Range: Set crg = .Resize(.Worksheet.Rows.Count - .Row + 1)
End With
' Write the values from the Column Range to the Column Data Array ('cData').
Dim cData As Variant
If crg.Rows.Count = 1 Then ' only one cell
ReDim cData(1 To 1, 1 To 1): cData(1, 1) = crg.Value
Else
cData = crg.Value
End If
' Loop.
Dim r As Long
' Loop through the elements of the Column Data Array...
For r = 1 To UBound(cData, 1)
' ... until an empty value is found.
If IsEmpty(cData(r, 1)) Then
' Create a reference to the r-th cell of the Column Range.
Set RefFirstEmptyCellInColumn = crg.Cells(r)
Exit Function
End If
Next r
End Function
The Test
To test the previous you can do the following.
Sub RefFirstEmptyCellInColumnTEST()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim fCell As Range: Set fCell = ws.Range("A3")
' Empty
Dim feCell As Range: Set feCell = RefFirstEmptyCellInColumn(fCell)
If Not feCell Is Nothing Then
Debug.Print feCell.Address(0, 0)
End If
End Sub
Blank
You can do the same for blank cells i.e. empty cells or cells containing a single quote (') or cells containing formulas evaluating to "". Note that cells containing spaces are neither blank nor empty.
Function RefFirstBlankCellInColumnBasic( _
ByVal FirstCell As Range) _
As Range ' (Empty, ="" and ')
' Validate the given range ('FirstCell').
If FirstCell Is Nothing Then Exit Function
' Create a reference to the Column Range ('crg').
With FirstCell.Cells(1)
Dim crg As Range: Set crg = .Resize(.Worksheet.Rows.Count - .Row + 1)
End With
' Loop.
Dim cCell As Range
' Loop through the cells of the Column Range...
For Each cCell In crg.Cells
' (exclude cell containing error value)
If Not IsError(cCell) Then
' ... until a blank cell is found.
If Len(cCell.Value) = 0 Then
' Create a reference to the current cell.
Set RefFirstBlankCellInColumnBasic = cCell
Exit Function
End If
End If
Next cCell
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the top-most blank cell
' in the one-column range from the first cell of a range
' ('FirstCell') through the last cell in its column.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefFirstBlankCellInColumn( _
ByVal FirstCell As Range) _
As Range ' (Empty, ="" and ')
' Validate the given range ('FirstCell').
If FirstCell Is Nothing Then Exit Function
' Create a reference to the Column Range ('crg').
With FirstCell.Cells(1)
Dim crg As Range: Set crg = .Resize(.Worksheet.Rows.Count - .Row + 1)
End With
' Write the values from the Column Range to the Column Data Array ('cData').
Dim cData As Variant
If crg.Rows.Count = 1 Then ' only one cell
ReDim cData(1 To 1, 1 To 1): cData(1, 1) = crg.Value
Else
cData = crg.Value
End If
' Loop.
Dim r As Long
' Loop through the elements of the Column Data Array...
For r = 1 To UBound(cData, 1)
' (exclude error values)
If Not IsError(cData(r, 1)) Then
' ... until a blank is found.
If Len(cData(r, 1)) = 0 Then
' Create a reference to the r-th cell of the Column Range.
Set RefFirstBlankCellInColumn = crg.Cells(r)
Exit Function
End If
End If
Next r
End Function
Sub RefFirstBlankCellInColumnTEST()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim fCell As Range: Set fCell = ws.Range("A3")
' Blank
Dim fbCell As Range: Set fbCell = RefFirstBlankCellInColumn(fCell)
If Not fbCell Is Nothing Then
Debug.Print fbCell.Address(0, 0)
End If
End Sub

Column Table convert Matrix Table in VBA code

Current i using formula(index and Match) to create matrix i wish using VBA coding, this will make more fast compair to formula. Thanks in advance
enter image description here
Sub columntomatrix
Dim mS As Worksheet
Dim eS As Worksheet
Set mS = ThisWorkbook.Sheets("Matrix")
Set eS = ThisWorkbook.Sheets("Price Entry Book")
Dim Matrix() As String
Dim entryPrice() As String
Dim Product As Range
Dim PriceBook As Range
Set Product = Range("Product")
Set PriceBook = Range("PriceBookName")
With mS.Range("B2")
.Formula = "=IFERROR(INDEX(ListPrice,
MATCH(" & .Offset(0,-1).Address(False, True) & "&" &
.Offset(-1, 0).Address(True, False) & ",ProductKey,0)),"" N/A "")"
Product.Copy
'offset(0,-1) = selected cells move to left 1 column'
.Offset(0, -1).PasteSpecial
PriceBook.Copy
.offset(-1,0) = selected cells move to up 1 row'
.Offset(-1, 0).PasteSpecial Paste:=xlPasteAll, Transpose:=True
With Range(.Offset(0, 0), .Offset(Product.Rows.Count - 2, PriceBook.Rows.Count - 2))
.FillDown
.FillRight
End with
End with
End Sub
Pivot RCV
Copy all four procedures to a standard module, e.g. Module1.
Carefully adjust the values in the Define constants. section of pivotRCV.
Only run the first procedure pivotRCV, the others are being called by it.
The Code
Option Explicit
Sub pivotRCV() ' RCV: Row Labels, Column Labels, and Values
' Define constants.
' Define Source constants.
Const srcName As String = "Price Entry Book"
Const srcFirst As String = "A2"
Const rlCol As Long = 1
Const clCol As Long = 2
Const vCol As Long = 4
Const rlSort As Boolean = False
Const clSort As Boolean = False
' Define Target constants.
Const tgtName As String = "Matrix"
Const tgtFirst As String = "A2"
' Define workbooks.
Dim src As Workbook
Set src = ThisWorkbook
Dim tgt As Workbook
Set tgt = ThisWorkbook
' Define Source Range.
' Define Source Worksheet.
Dim ws As Worksheet
Set ws = src.Worksheets(srcName)
' Define Source Range.
Dim rng As Range
Set rng = defineEndRange(ws.Range(srcFirst))
' Write values from Source Range to arrays.
' Write values from Source Range to 1D Unique Row Labels Array.
Dim rLabels As Variant
rLabels = getUniqueColumn1D(rng.Columns(rlCol).Resize(rng.Rows.Count - 1) _
.Offset(1))
If rlSort Then
sort1D rLabels
End If
' Write values from Source Range to 1D Unique Column Labels Array.
Dim cLabels As Variant
cLabels = getUniqueColumn1D(rng.Columns(clCol).Resize(rng.Rows.Count - 1) _
.Offset(1))
If clSort Then
sort1D cLabels
End If
' Write values from Source Range to 2D Source Array.
Dim Source As Variant
Source = rng.Value
' Prepare to write values from Source Array to Target Array.
' Define Target Array.
Dim Target As Variant
ReDim Target(1 To UBound(rLabels) - LBound(rLabels) + 2, _
1 To UBound(cLabels) - LBound(cLabels) + 2)
' Define counters.
Dim n As Long
Dim i As Long
i = 1
' Write values from Source Arrays to Target Array.
' Write first row/column label.
Target(1, 1) = Source(1, 1)
' Write row labels.
For n = LBound(rLabels) To UBound(rLabels)
i = i + 1
Target(i, 1) = rLabels(n)
Next n
' Write column labels.
Dim j As Long
j = 1
For n = LBound(cLabels) To UBound(cLabels)
j = j + 1
Target(1, j) = cLabels(n)
Next n
' Write values.
For n = 2 To UBound(Source, 1)
i = Application.Match(Source(n, rlCol), rLabels, 0) + 1
j = Application.Match(Source(n, clCol), cLabels, 0) + 1
Target(i, j) = Source(n, vCol)
Next n
' Write values from Target Array to Target Range.
' Define Target Worksheet.
Set ws = tgt.Worksheets(tgtName)
' Define Target First Row Range.
With ws.Range(tgtFirst).Resize(, UBound(Target, 2))
' Clear contents from Target First Row Range to the bottom-most row.
.Resize(ws.Rows.Count - .Row + 1).ClearContents
' Define Target Range.
Set rng = .Resize(UBound(Target, 1))
End With
' Write values from Target Array to Target Range.
rng.Value = Target
' Inform user.
MsgBox "Data transferred.", vbInformation, "Success"
End Sub
' Defines the range from a specified first cell to the last cell
' of its Current Region.
Function defineEndRange(FirstCellRange As Range) _
As Range
' Define Current Region ('rng').
Dim rng As Range
Set rng = FirstCellRange.CurrentRegion
' Define End Range.
Set defineEndRange = FirstCellRange _
.Resize(rng.Rows.Count + rng.Row - FirstCellRange.Row, _
rng.Columns.Count + rng.Column - FirstCellRange.Column)
End Function
' Returns the unique values from a column range.
Function getUniqueColumn1D(ColumnRange As Range, _
Optional ByVal Sorted As Boolean = False) _
As Variant
Dim Data As Variant
Data = ColumnRange.Columns(1).Value
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
Dim Key As Variant
Dim i As Long
For i = 1 To UBound(Data, 1)
Key = Data(i, 1)
If Not IsError(Key) And Not IsEmpty(Key) Then
.Item(Key) = Empty
End If
Next i
getUniqueColumn1D = .Keys
End With
End Function
' Sorts a 1D array only if it contains the same data type.
Sub sort1D(ByRef OneD As Variant, _
Optional ByVal Descending As Boolean = False)
With CreateObject("System.Collections.ArrayList")
Dim i As Long
For i = LBound(OneD) To UBound(OneD)
.Add OneD(i)
Next i
.Sort
If Descending Then
.Reverse
End If
OneD = .ToArray
End With
End Sub

sumif with dynamic column and range in VBA

I want to using sumifs function in VBA. And result paste in same column as previous data.
Twice a SUMIF with Overwrite
Workbook
Download
(Dropbox)
Couldn't find any indication of SUMIFS, so I did it as if there is
twice a SUMIF:
For Columns A and C, and for Columns B and D.
Option Explicit
Sub SumUnique(UniqueFirstCell As Range, ValueFirstCell As Range)
Dim rng As Range ' Unique Last Used Cell
Dim dict As Object ' Dictionary
Dim key As Variant ' Dictionary Key Counter (For Each Control Variable)
Dim vntU As Variant ' Unique Range Array
Dim vntV As Variant ' Value Range Array
Dim vntUT As Variant ' Unique Array
Dim vntVT As Variant ' Value Array
Dim curV As Variant ' Current Value
Dim NorS As Long ' Source Number of Rows
Dim NorT As Long ' Target Number of Rows
Dim i As Long ' Source/Target Row Counter
' Copy Unique Range to Unique Range Array.
With UniqueFirstCell
Set rng = .Worksheet.Columns(.Column) _
.Find("*", , xlFormulas, , , xlPrevious)
Set rng = .Resize(rng.Row - .Row + 1)
End With
vntU = rng
' Copy Value Range to Value Range Array.
With ValueFirstCell
Set rng = .Worksheet.Columns(.Column) _
.Find("*", , xlFormulas, , , xlPrevious)
Set rng = .Resize(rng.Row - .Row + 1)
End With
vntV = rng
' Create Unique Values and SumIf Values in Dictionary.
Set dict = CreateObject("Scripting.Dictionary")
NorS = UBound(vntU)
For i = 1 To NorS
curV = vntU(i, 1)
If curV <> "" Then
dict(curV) = dict(curV) + vntV(i, 1)
End If
Next
NorT = dict.Count
' Resize Unique and Value Arrays to Target Number of Rows.
ReDim vntUT(1 To NorT, 1 To 1)
ReDim vntVT(1 To NorT, 1 To 1)
i = 0
For Each key In dict.keys
i = i + 1
' Write Dictionary Keys to Unique Array.
vntUT(i, 1) = key
' Write Dictionary Values to Value Array.
vntVT(i, 1) = dict(key)
Next
' Copy Unique Array to Target Unique Range.
With UniqueFirstCell
Set rng = .Resize(.Worksheet.Rows.Count - .Row + 1)
rng.ClearContents
Set rng = .Resize(NorT)
End With
rng = vntUT
' Copy Value Array to Target Value Range.
With ValueFirstCell
Set rng = .Resize(.Worksheet.Rows.Count - .Row + 1)
rng.ClearContents
Set rng = .Resize(NorT)
End With
rng = vntVT
End Sub
Sub Uni()
Uni1
Uni2
End Sub
Sub Uni1()
Const cUni As String = "A2"
Const cVal As String = "C2"
With ThisWorkbook.Worksheets("Sheet1")
SumUnique .Range(cUni), .Range(cVal)
End With
End Sub
Sub Uni2()
Const cUni As String = "B2"
Const cVal As String = "D2"
With ThisWorkbook.Worksheets("Sheet1")
SumUnique .Range(cUni), .Range(cVal)
End With
End Sub
I created two command buttons and put the following code into the sheet module:
Option Explicit
Private Sub cmdRevert_Click()
[A2:D31] = [J2:M31].Value
End Sub
Private Sub cmdUnique_Click()
Uni
End Sub
You can use SumIfs in VBA through the Application or WorksheetFunction object with VBA style range references. You are only going to want to use it once for each pair of column A and column B values. If you use it once then loop to another row with the same pair of column A and column B values, you cannot use it again without getting false results due to the changes you made the first time.
However, those false results are okay if you are just going to delete them anyways and RemoveDuplicates deletes from the bottom up leaving the top-most column A and column B pairs with the correct totals.

how to merge cells with same value in one row

How do I merge cells with the same value and color in a row?
and the result should be :
I think you could try this:
Option Explicit
Sub test()
Dim LastRow As Long, i As Long, Value As Long
Dim Color As Double
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = LastRow To 2 Step -1
Value = .Range("A" & i).Value
Color = .Range("A" & i).Interior.Color
If .Range("A" & i - 1).Value = Value And .Range("A" & i - 1).Interior.Color = Color Then
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub
Copy Consecutive to One
Adjust the values in the constants section to fit your needs.
The image looks like you want all this to happen in the same column
of the same worksheet, which is adjusted in the constants section.
Before writing to Target Column (cTgtCol), the code will clear its
contents. Be careful not to lose data.
Colors are applied using a loop, which will slow down the fast array approach of copying the data.
The Code
Sub CopyConsecutiveToOne()
' Source
Const cSource As Variant = "Sheet1" ' Worksheet Name/Index
Const cSrcCol As Variant = "A" ' Column Letter/Number
Const cSrcFR As Long = 1 ' Column First Row Number
' Target
Const cTarget As Variant = "Sheet1" ' Worksheet Name/Index
Const cTgtCol As Variant = "A" ' Column Letter/Number
Const cTgtFR As Long = 1 ' Column First Row Number
Dim rng As Range ' Source Column Last Used Cell Range,
' Source Column Range, Target Column Range
Dim vntS As Variant ' Source Array
Dim vntT As Variant ' Target Array
Dim vntC As Variant ' Color Array
Dim i As Long ' Source Range/Array Row/Element Counter
Dim k As Long ' Target/Color Array Element Counter
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'On Error GoTo ProcedureExit
' In Source Worksheet
With ThisWorkbook.Worksheets(cSource).Columns(cSrcCol)
' Calculate Source Column Last Used Cell Range.
Set rng = .Find("*", , xlFormulas, xlWhole, xlByColumns, xlPrevious)
' Check if data in Source Column.
If Not rng Is Nothing Then ' Data found.
' Calculate Source Range.
Set rng = .Range(.Cells(cSrcFR), .Cells(rng.Row))
' Copy values from Source Range to Source Array.
vntS = rng
Else ' Data Not Found.
With .Cells(1)
MsgBox "No Data in column '" & .Split(.Address, "$")(1) & "'."
GoTo ProcedureExit
End With
End If
End With
' In Arrays
' Count the number of elements in Target/Color Array.
k = 1 ' The first element will be included before the loop.
' Loop through elements of Source Array.
For i = 2 To UBound(vntS)
' Check if current value is different then the previous one.
If vntS(i, 1) <> vntS(i - 1, 1) Then
' Count element of Target/Color Array.
k = k + 1
End If
Next
' Write to Target/Color Arrays
' Resize Target/Color Arrays.
ReDim vntT(1 To k, 1 To 1)
ReDim vntC(1 To k, 1 To 1)
' Reset Counter
k = 1 ' The first element will be included before the loop.
' Write first value from Source Array to Target Array.
vntT(1, 1) = vntS(1, 1)
' Write first color value to Target Color Array.
vntC(1, 1) = rng.Cells(1, 1).Interior.Color
' Loop through elements of Source Array.
For i = 2 To UBound(vntS)
' Check if current value is different then the previous one.
If vntS(i, 1) <> vntS(i - 1, 1) Then
' Count element of Target/Color Array.
k = k + 1
' Write from Source Array to Target Array.
vntT(k, 1) = vntS(i, 1)
' Write color values from Source Range to Color Array.
vntC(k, 1) = rng.Cells(i, 1).Interior.Color
End If
Next
' All necessary data is in Target/Color Arrays.
Erase vntS
Set rng = Nothing
' In Target Worksheet
With ThisWorkbook.Worksheets(cTarget).Cells(cTgtFR, cTgtCol)
' Clear contents of range from Target First Cell to Target Bottom Cell.
.Resize(Rows.Count - .Row + 1).ClearContents
' Calculate Target Column Range.
Set rng = .Resize(k)
' Copy Target Array to Target Range.
rng = vntT
' Apply colors to Target Range.
With rng
' Loop through cells of Target Column Range.
For i = 1 To k
' Apply color to current cell of Target Range using the values
' from Color Array.
.Cells(i, 1).Interior.Color = vntC(i, 1)
Next
End With
End With
ProcedureExit:
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End Sub
Create a custom function in Visual Basic Editor that will return to the color index of the cell:
Function COLOR(Target As Range)
COLOR = Target.Interior.ColorIndex
End Function
Then in the right column use a formula similar to this:
=IF(OR(A2<>A3,COLOR(A2)<>COLOR(A3)),1,0)
Then filter to show only 1's.

Resources