Compare 2 ranges add new items to end of range - excel

I have a range in column D and a range in column F. These ranges contain strings, the strings in column D are unique (i.e. they do not repeat) and the strings in column F are also unique. However, column D and F should both contain the same strings most of the time, although they may be in a different order. The strings look something similar to:
tag:(0004)X-axis
tag:(0005)Z-axis
tag:(0005)X-axis
tag:(0006)Z-axis
Sometimes column D may be missing some of the strings or it may have some new strings. I want to compare column D to column F and if there are new strings in column D, I want to add (append) them to the end of column F. Here is a simple Example using simply a,b,c instead of "tag:(00... bla... bla...":
Column D Column F
a b
b c
c d
e e
f g
g
Column D is missing "d" but has "a" and "f"... so "a" and "f" will be added (apended) to the end to column F, like this:
Column F
b
c
d
e
g
a
f
I was trying to use this as a less direct route but I can't even get this to work:
Sub RT_COMPILER()
Dim Lastrow As Long
Dim r As Long
Dim n As Long
For r = 1 To Lastrow
n = Application.WorksheetFunction.CountIf(Range("D:D"), Cells(r, 6))
If n = 0 Then
Cells(r, 7) = Cells(r, 4)
Else
Cells(r, 7) = ""
End If
Next
End Sub
My thinking was: If I could get the new strings into column G... then delete the blank spaces then copy and paste them appending them to the end of column F... but it seems to just identify that the last item in column D is "g" and the last item in column F is blank and it would pull a "g" out of the list even though it already had a "g"...
When I originally found this code it had:
n = Application.WorksheetFunction.CountIf("D:D", Cells(r, 6))
it didn't work so I changed it to:
n = Application.WorksheetFunction.CountIf(Range("D:D"), Cells(r, 6))

This could be a bit overkill for Excel development, but in the long run, it is a good idea to work with Dictionary data type, as it is optimized to store unique values. Thus, once you find a way to pass the cells data to a dictionary, this is a way to add the missing values of setA to setB:
Sub TestMe()
Dim setA As Object
Dim setB As Object
Set setA = CreateObject("Scripting.Dictionary")
Set setB = CreateObject("Scripting.Dictionary")
AddToDictionaryIfNotPresent "A", setA
AddToDictionaryIfNotPresent "B", setA
AddToDictionaryIfNotPresent "C", setA
AddToDictionaryIfNotPresent "D", setA
AddToDictionaryIfNotPresent "A", setB
AddToDictionaryIfNotPresent "B", setB
AddToDictionaryIfNotPresent "A", setB 'C is missing!
AddToDictionaryIfNotPresent "D", setB
Dim var As Variant
For Each var In setA
If Not ValueExistsInCollection(var, setB) Then
Debug.Print "Adding "; var
AddToDictionaryIfNotPresent var, setB
End If
Next
End Sub
And these are the additional functions:
Public Function AddToDictionaryIfNotPresent(myValue As Variant, myDictionary As Object)
If Not myDictionary.Exists(myValue) Then myDictionary.Add myValue, 1
End Function
Public Function ValueExistsInCollection(myValue As Variant, myDictionary As Object) As Boolean
Dim var As Variant
For Each var In myDictionary
If var = myValue Then
ValueExistsInCollection = True
Exit Function
End If
Next var
End Function
At the end, all the unique values are at setB:

I think your CountIf was looking in the wrong column.
I recommend the following approach:
Option Explicit
Public Sub CompareAndAppend()
Dim ws As Worksheet 'define worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "D").End(xlUp).Row
Dim NextFreeRow As Long
NextFreeRow = ws.Cells(ws.Rows.Count, "F").End(xlUp).Row + 1
Dim cnt As Long
Dim iRow As Long
For iRow = 1 To LastRow 'loop through column D
cnt = Application.WorksheetFunction.CountIf(ws.Range("F:F"), ws.Cells(iRow, "D"))
If cnt = 0 Then 'this value is missing in F, append it
ws.Cells(NextFreeRow, "F").Value = ws.Cells(iRow, "D")
NextFreeRow = NextFreeRow + 1 'move to next free row
End If
Next iRow
End Sub
The red ones were added.
A probably faster version would be using arrays and a dictionary:
Public Sub CompareAndAppendSpeedyGonzales()
Dim ws As Worksheet 'define worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim InputArr() As Variant
InputArr = ws.Range("D1", ws.Cells(ws.Rows.Count, "D").End(xlUp)).Value
Dim CompareArr() As Variant
CompareArr = ws.Range("F1", ws.Cells(ws.Rows.Count, "F").End(xlUp)).Value
Dim AppendArr As Variant
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim i As Long
'add column F
For i = LBound(CompareArr, 1) To UBound(CompareArr, 1)
If Not dict.exists(CompareArr(i, 1)) Then
dict.Add CompareArr(i, 1), 0
End If
Next i
'add column D
For i = LBound(InputArr, 1) To UBound(InputArr, 1)
If Not dict.exists(InputArr(i, 1)) Then
dict.Add InputArr(i, 1), 0
If IsEmpty(AppendArr) Then
ReDim AppendArr(1 To 1)
AppendArr(1) = InputArr(i, 1)
Else
ReDim Preserve AppendArr(1 To UBound(AppendArr) + 1)
AppendArr(UBound(AppendArr)) = InputArr(i, 1)
End If
End If
Next i
ws.Cells(ws.Rows.Count, "F").End(xlUp).Offset(1, 0).Resize(RowSize:=UBound(AppendArr)).Value = Application.WorksheetFunction.Transpose(AppendArr)
End Sub

Option Explicit
Sub test()
Dim LastrowD As Long, i As Long, LastrowF As Long, Times As Long
Dim cell As Range, rngToSearch As Range
Dim str As String
With ThisWorkbook.Worksheets("Sheet5")
LastrowD = .Cells(.Rows.Count, "D").End(xlUp).Row
For i = 1 To LastrowD
str = .Range("D" & i).Value
LastrowF = .Cells(.Rows.Count, "F").End(xlUp).Row
Set rngToSearch = .Range("F1:F" & LastrowF)
Times = Application.WorksheetFunction.CountIf(rngToSearch, str)
If Times = 0 Then
.Range("F" & LastrowF + 1) = str
End If
Next i
End With
End Sub

Related

Getting unique values for multiple column separatly

What is worng with my function its loading the two different column A and B and pasting the unique values of column A into Column M and N.
I want to repeat this function for the 7 columns.
I would appreciate your help in this regards.
Sub GetUniques()
Dim d As Object, c As Variant, i As Long, lr As Long, lr2 As Long, lr3 As Long, lr4 As Long, lr5 As Long, lr6 As Long
Set d = CreateObject("Scripting.Dictionary")
lr = Cells(Rows.Count, 1).End(xlUp).Row
c = Range("A2:A" & lr)
lr2 = Cells(Rows.Count, 2).End(xlUp).Row
e = Range("B2:B" & lr2)
For i = 1 To UBound(c, 1)
d(c(i, 1)) = 1
Next i
For i = 1 To UBound(e, 1)
d(e(i, 1)) = 1
Next i
Range("M2").Resize(d.Count) = Application.Transpose(d.keys)
Range("N2").Resize(d.Count) = Application.Transpose(d.keys)
End Sub
It looks like your plan is to have a lr variable for each column as well as loops and transpose statements. You can avoid this by nesting your code in a column loop.
The current Column range is hard coded here (A to E) but this can be updated to be dynamic as needed. The output is also hard coded to be dropped 9 columns to the right of the input column. This aligns with A to J, B to K, etc.
Sub GetUniques()
Dim c As Variant, i As Long, lr As Long, col As Long
Dim d As Object
For col = 1 To 5 'Column A to E
Set d = CreateObject("Scripting.Dictionary")
lr = Cells(Rows.Count, col).End(xlUp).Row
c = Range(Cells(2, col), Cells(lr, col))
For i = 1 To UBound(c, 1)
d(c(i, 1)) = 1
Next i
Cells(2, col + 9).Resize(d.Count) = Application.Transpose(d.keys)
Set d = Nothing
Next col
End Sub
I am adding the UNIQUE- solution - for completeness:
You can either use a manual formula in J2: =UNIQUE(A:E,TRUE) - the second parameter tells UNIQUE to put out unique values per column --> it will spill from J to N.
You can use this formula in a VBA-routine as well:
Public Sub writeUniqueValues(rgSource As Range, rgTargetTopLeftCell As Range)
With rgTargetTopLeftCell
.Formula2 = "=UNIQUE(" & rgSource.Address & ",TRUE)"
With .SpillingToRange
.Value = .Value 'this will replace the formula by values
End With
End With
End Sub
You can then use this sub like this:
Public Sub test_writeUniqueValues()
With ActiveSheet 'be careful: you should always use explicit referencing
Dim lr As Long
lr = .Cells(Rows.Count, 1).End(xlUp).Row
writeUniqueValues .Range("A2:E" & lr), .Range("J2")
End With
End Sub
It would be interesting to compare performance of both solutions (using the formula vs. using a dictionary) ...

Application Match Function how to copy paste data

Using Application.Match Function but unable to know how to paste the Col"M" data into Col"P" after the Matching the Col"O" and Col"L".
When run the Current function it gives the count of match.
Any help will be appreciated.
Dim k As Integer
For k = 2 To 9
ws2.Cells(k, 16).Value = Application.Match(ws2.Cells(k, 15).Value, ws2.Range("L2:L9"), 0)
Next k
I have edited the code with the columns and in which column the result is required. But unable to make changes I really appreciate your help that you make this function. I added some comments may it can help.
' Sheet2 Col"C" with ID's
With ws2
Dim lastRow As Long
lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Dim originalData() As Variant
originalData = .Range("C2:C" & lastRow).Value
End With
' Sheet2 Col"C" with ID's
With ws3
Dim lastRow2 As Long
lastRow2 = .Range("A" & .Rows.Count).End(xlUp).Row
Dim newData() As Variant
newData = .Range("C2:C" & lastRow2).Value
End With
Dim i As Long
For i = LBound(newData, 1) To UBound(newData, 1)
Dim j As Long
For j = LBound(originalData, 1) To UBound(originalData, 2)
If newData(i, 1) = originalData(j, 1) Then
newData(i, 2) = originalData(j, 2)
Exit For
End If
Next
Next
'Sheet2 Col"K" where Sheet3 Col"E" data will be pasted
ws2.Range("K2:K" & lastRow).Value = newData
A scripting dictionary which maps "keys" to "values" is typically the fastest approach when you need to perform a lot of lookups. It's a bit more code to write but should be quick.
Sub DoLookup()
Dim arrKeys, arrValues, wsData As Worksheet, wsDest As Worksheet
Dim map As Object, rngSearch As Range, rngResults As Range, k, v, n As Long
Set wsData = ThisWorkbook.Worksheets("Sheet3") 'sheet with the lookup table
Set wsDest = ThisWorkbook.Worksheets("Sheet2") 'sheet to be populated
arrKeys = wsData.Range("C2:C" & LastRow(wsData, "C")).Value 'keys in the lookup table
arrValues = wsData.Range("G2:G" & LastRow(wsData, "C")).Value 'values in the lookup table
Set map = MapValues(arrKeys, arrValues) 'get a map of Keys->Values
Set rngSearch = wsDest.Range("C2:C" & LastRow(wsDest, "c")) 'keys to look up
Set rngResults = rngSearch.EntireRow.Columns("K") 'results go here
arrKeys = rngSearch.Value 'keys to look up
arrValues = rngResults.Value 'array to populate with results
For n = 1 To UBound(arrKeys) 'loop over keys to look up
v = "" 'or whatever you want to see if no match
k = arrKeys(n, 1)
If map.exists(k) Then v = map(k)
arrValues(n, 1) = v
Next n
rngResults.Value = arrValues 'populate the results array back to the sheet
End Sub
'Return a Scripting Dictionary linking "keys" to "values"
' Note - assumes same-size single-column inputs, and that keys are unique,
' otherwise you just map to the *last* value for any given key
Function MapValues(arrKeys, arrValues)
Dim n, dict As Object, k
Set dict = CreateObject("scripting.dictionary")
For n = 1 To UBound(arrKeys, 1)
k = CStr(arrKeys(n, 1)) 'string keys are faster to add?
If Len(k) > 0 Then dict(k) = arrValues(n, 1)
Next n
Set MapValues = dict
End Function
'utility function
Function LastRow(ws As Worksheet, col As String) As Long
LastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
End Function
In my test workbook this was able to perform 10k lookups against a table of 10k rows in <0.1 sec.
You always should test if the Match succeeded, using IsError.
Then use Cells:
Dim k As Long
For k = 2 To 9
Dim m As Variant
m = Application.Match(ws2.Cells(k, 15).Value, ws2.Range("L2:L9"), 0)
If Not IsError(m) Then
ws2.Cells(k, 16).Value = ws2.Range("M2:M9").Cells(m)
End If
Next

Remove duplicates from column A based on existing values in column B using VBA

I need to input data in column A and column B and get the data that's in column A but not in column B written to column C.
Examples of what I need:
A slightly different and faster approach without looping through cells on the sheet would be this...
Private Sub CommandButton1_Click()
Dim x, y(), dict
Dim i As Long, j As Long
x = Range("A1").CurrentRegion
Set dict = CreateObject("Scripting.Dictionary")
Columns("C").ClearContents
For i = 1 To UBound(x, 1)
dict.Item(x(i, 2)) = ""
Next i
j = 1
For i = 1 To UBound(x, 1)
If Not dict.exists(x(i, 1)) Then
ReDim Preserve y(1 To j)
y(j) = x(i, 1)
j = j + 1
End If
Next i
Range("C1").Resize(UBound(y), 1) = Application.Transpose(y)
End Sub
Place this in the code file behind your sheet and change CommandButton1 to the name of your button.
Option Explicit
Private Sub CommandButton1_Click()
Dim r As Range, matched_ As Variant, counter_ As Long
'Loop in each cell in Column A
For Each r In Range("A1:A" & Cells(Rows.Count, 1).End(xlUp).Row)
If Not IsEmpty(r) Then
'Loop for a matching value in Column B
matched_ = Application.Match(r.Value, Columns(2), 0)
'If match not found, write the value in Column C
If IsError(matched_) Then
counter_ = counter_ + 1
Range("C" & counter_) = r.Value
End If
End If
Next r
End Sub

vba - loop through 3 columns

There are 4 columns on my excel.
For every element in column A, I would like to loop through every element column C. If the element in column C equal to column A, then it return the value of column D in column B.
For example, B4 should return "dog". B5 should return "egg". B6 should return "cat".
I ran my VBA code. All the value in column B returns "egg". Could someone have a look with my below VBA code please?
Sub testing_click()
Dim x As Variant
Dim arr1 As Variant
Dim i , r As Long
arr1 = Worksheets("testing").Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row).Value
For Each x In arr1
For r = 1 To 5
If x = Trim(Worksheets("testing").Cells(r, "c").Value) Then
For i = 1 To Worksheets("testing").Range("a1048576").End(xlUp).Row
Worksheets("testing").Cells(i, "b").Value = Worksheets("testing").Cells(r, "d").Value
Next i
End If
Next r
Next x
End Sub
Just had one too many loops in there. What it was actually doing was finding the first value correctly, and putting it in all 12 rows of column "B". Then finding the second value, and re-assigning all 12 rows of column "B".
Get rid of the innermost loop, add counter in it's place with the same name, and you're good to go. Now, instead of looking through all cells in column "A", it only looks through the populated ones, and will terminate the inner loop as soon as it has a match.
Also corrected a mistake in the declarations. Dim i, r As Long actually only casts r as long, and i as Variant. Dim i as Long, r as Long will capture them both as Long types.
Hope it helps!
Sub testing_click()
Dim x As Variant
Dim arr1 As Variant
Dim i as Long, r As Long
arr1 = Worksheets("testing").Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row).Value
'initialize row counter out here
i = 1
For Each x In arr1
For r = 1 To 5
If x = Trim(Worksheets("testing").Cells(r, "c").Value) Then
Worksheets("testing").Cells(i, "b").Value = Worksheets("testing").Cells(r, "d").Value
'Increment row counter and exit inner loop
i = i + 1
Exit For
End If
Next r
Next x
End Sub
arr1 must be Dim'ed as array ... e.g. Dim arr1() As Variant
I also recommend to substitute the End(xlUpDownLeftRightHomeEnd)'s by more VBA like loop constructs, e.g.
Sub ClassicalLoops()
Dim OuterLoop As Integer, InnerLoop As Integer
Dim DataRange As Range, LookupRange As Range
Set DataRange = [A1]
Set LookupRange = [C1]
OuterLoop = 1
Do While DataRange(OuterLoop, 1) <> ""
InnerLoop = 1
Do While LookupRange(InnerLoop, 1) <> ""
If DataRange(OuterLoop, 1) = LookupRange(InnerLoop, 1) Then
DataRange(OuterLoop, 2) = LookupRange(InnerLoop, 2)
Exit Do
Else
InnerLoop = InnerLoop + 1
End If
Loop
OuterLoop = OuterLoop + 1
Loop
End Sub

Remove duplicates from array using VBA

Assume I have a block of data in Excel 2010, 100 rows by 3 columns.
Column C contains some duplicates, say it starts off as
1, 1, 1, 2, 3, 4, 5, ..... , 97, 98
Using VBA, I would like to remove the duplicate rows so I am left with 98 rows and 3 columns.
1, 2, 3, ..... , 97, 98
I know there is a button in Excel 2010 to do that but it inteferes with the rest of my code subsequently and gives incorrect results.
Furthermore, I would like to do it in arrays, then paste the results on the worksheet, rather than methods such as Application.Worksheetfunction.countif(.....
So something like:
Dim myarray() as Variant
myarray=cells(1,1).Currentregion.value
Dim a as Long
For a=1 to Ubound(myarray,1)
'something here to
Next a
I answered a similar question. Here is the code I used:
Dim dict As Object
Dim rowCount As Long
Dim strVal As String
Set dict = CreateObject("Scripting.Dictionary")
rowCount = Sheet1.Range("A1").CurrentRegion.Rows.Count
'you can change the loop condition to iterate through the array rows instead
Do While rowCount > 1
strVal = Sheet1.Cells(rowCount, 1).Value2
If dict.exists(strVal) Then
Sheet1.Rows(rowCount).EntireRow.Delete
Else
'if doing this with an array, then add code in the Else block
' to assign values from this row to the array of unique values
dict.Add strVal, 0
End If
rowCount = rowCount - 1
Loop
Set dict = Nothing
If you want to use an array, then loop through the elements with the same conditional (if/else) statements. If the item doesn't exist in the dictionary, then you can add it to the dictionary and add the row values to another array.
Honestly, I think the most efficient way is to adapt code you'd get from the macro recorder. You can perform the above function in one line:
Sheet1.UsedRange.RemoveDuplicates Columns:=3, Header:=xlYes
Function eliminateDuplicate(poArr As Variant) As Variant
Dim poArrNoDup()
dupArrIndex = -1
For i = LBound(poArr) To UBound(poArr)
dupBool = False
For j = LBound(poArr) To i
If poArr(i) = poArr(j) And Not i = j Then
dupBool = True
End If
Next j
If dupBool = False Then
dupArrIndex = dupArrIndex + 1
ReDim Preserve poArrNoDup(dupArrIndex)
poArrNoDup(dupArrIndex) = poArr(i)
End If
Next i
eliminateDuplicate = poArrNoDup
End Function
Simple function to remove duplicates from a 1D array
Private Function DeDupeArray(vArray As Variant) As Variant
Dim oDict As Object, i As Long
Set oDict = CreateObject("Scripting.Dictionary")
For i = LBound(vArray) To UBound(vArray)
oDict(vArray(i)) = True
Next
DeDupeArray = oDict.keys()
End Function
Edit:
With stdVBA (a library largely maintained by myself) you can use:
uniqueValues = stdEnumerator.CreateFromArray(myArray).Unique().AsArray()
An improvement on #RBILLC and #radoslav006 answers, this version searches the array with the duplicates removed for existing values so it searchs less values to find a duplicate.
Public Function RemoveDuplicatesFromArray(sourceArray As Variant)
Dim duplicateFound As Boolean
Dim arrayIndex As Integer, i As Integer, j As Integer
Dim deduplicatedArray() As Variant
arrayIndex = -1
deduplicatedArray = Array(1)
For i = LBound(sourceArray) To UBound(sourceArray)
duplicateFound = False
For j = LBound(deduplicatedArray) To UBound(deduplicatedArray)
If sourceArray(i) = deduplicatedArray(j) Then
duplicateFound = True
Exit For
End If
Next j
If duplicateFound = False Then
arrayIndex = arrayIndex + 1
ReDim Preserve deduplicatedArray(arrayIndex)
deduplicatedArray(arrayIndex) = sourceArray(i)
End If
Next i
RemoveDuplicatesFromArray = deduplicatedArray
End Function
Here's another approach for working with an array:
Sub tester()
Dim arr, arrout
arr = Range("A1").CurrentRegion.Value 'collect the input array
arrout = UniqueRows(arr) 'get only unique rows
Range("H1").Resize(UBound(arrout, 1), UBound(arrout, 2)).Value = arrout
End Sub
Function UniqueRows(arrIn As Variant) As Variant
Dim keys, rw As Long, col As Long, k, sep, arrout
Dim dict As Object, lbr As Long, lbc As Long, ubr As Long, ubc As Long, rwOut As Long
Set dict = CreateObject("scripting.dictionary")
'input array bounds
lbr = LBound(arrIn, 1)
ubr = UBound(arrIn, 1)
lbc = LBound(arrIn, 2)
ubc = UBound(arrIn, 2)
ReDim keys(lbr To ubr)
'First pass:collect all the row "keys" in an array
' and unique keys in a dictionary
For rw = lbr To ubr
k = "": sep = ""
For col = lbc To ubc
k = k & sep & arrIn(rw, col)
sep = Chr(0)
Next col
keys(rw) = k 'collect key for this row
dict(k) = True 'just collecting unique keys
Next rw
'Resize output array to # of unique rows
ReDim arrout(lbr To dict.Count + (lbr - 1), lbc To ubc)
rwOut = lbr
'Second pass: copy each unique row to the output array
For rw = lbr To ubr
If dict(keys(rw)) Then 'not yet output?
For col = lbc To ubc 'copying this row over to output...
arrout(rwOut, col) = arrIn(rw, col)
Next col
rwOut = rwOut + 1 'increment output "row"
dict(keys(rw)) = False 'flag this key as copied
End If
Next rw
UniqueRows = arrout
End Function
Answer from #RBILLC could be easily improved by adding an Exit For inside internal loop:
Function eliminateDuplicate(poArr As Variant) As Variant
Dim poArrNoDup()
dupArrIndex = -1
For i = LBound(poArr) To UBound(poArr)
dupBool = False
For j = LBound(poArr) To i
If poArr(i) = poArr(j) And Not i = j Then
dupBool = True
Exit For
End If
Next j
If dupBool = False Then
dupArrIndex = dupArrIndex + 1
ReDim Preserve poArrNoDup(dupArrIndex)
poArrNoDup(dupArrIndex) = poArr(i)
End If
Next i
eliminateDuplicate = poArrNoDup
End Function
I think this is really a case for using excel's native functions, at least for the initial array acquisition, and I don't think there's any simpler way to do it. This sub will output the unique values starting in column 5. I assumed that the target range was empty, so if it's not, change r and c.
Sub testUniques()
Dim arr, r As Long, c As Long, h As Long, w As Long
Dim this As Worksheet: Set this = ActiveSheet
arr = Application.Unique(this.Cells(1, 1).CurrentRegion)
r = 1
c = 5
h = UBound(arr, 1) - 1
w = UBound(arr, 2) - 1
this.Range(this.Cells(r, c), this.Cells(r + h, c + w)) = arr
End Sub
I know this is old, but here's something I used to copy duplicate values to another range so that I could see them quickly to establish data integrity for a database I was standing up from various spreadsheets. To make the procedure delete the duplicates it would be as simple as replacing the dupRng lines with Cell.Delete Shift:=xlToLeft or something to that effect.
I haven't tested that personally, but it should work.
Sub PartCompare()
Dim partRng As Range, partArr() As Variant, i As Integer
Dim Cell As Range, lrow As Integer
lrow = ThisWorkbook.Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
i = 0
Set partRng = ThisWorkbook.Worksheets("Sheet1").Range(Cells(1, 1), Cells(lrow, 1))
For Each Cell In partRng.Cells
ReDim Preserve partArr(i)
partArr(i) = Cell.Value
i = i + 1
Next
Dim dupRng As Range, j As Integer, x As Integer, c As Integer
Set dupRng = ThisWorkbook.Worksheets("Sheet1").Range("D1")
x = 0
c = 1
For Each Cell In partRng.Cells
For j = c To UBound(partArr)
If partArr(j) = Cell.Value Then
dupRng.Offset(x, 0).Value = Cell.Value
dupRng.Offset(x, 1).Value = Cell.Address()
x = x + 1
Exit For
End If
Next j
c = c + 1
Next Cell
End Sub
Remove duplicates (plus related row items) from array
As OP wanted a VBA solution close to RemoveDuplicates, I demonstrate an array approach using a â–ºdictionary to get not the unique items per se (dict.keys), but the related row indices of first occurrencies (dict.items).
These are used to retain the whole row data via procedure LeaveUniques profiting from the advanced possibilities of the â–ºApplication.Index() function - c.f. Some peculiarities of the the Application.Index function
Example Call
Sub ExampleCall()
'[0]define range and assign data to 1-based 2-dim datafield
With Sheet1 ' << reference to your project's sheet Code(Name)
Dim lastRow: lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
Dim rng: Set rng = .Range("C2:E" & lastRow)
End With
Dim data: data = rng ' assign data to 2-dim datafield
'[1]get uniques (column 1) and remove duplicate rows
LeaveUniques data ' << call procedure LeaveUniques (c.f. RemoveDuplicates)
'[2]overwrite original range
rng.Clear
rng.Resize(UBound(data), UBound(data, 2)) = data
End Sub
Procedure LeaveUniques
Sub LeaveUniques(ByRef data As Variant, Optional ByVal colNum As Long = 1)
'Purpose: procedure removes duplicates of given column number in entire array
data = Application.Index(data, uniqueRowIndices(data, colNum), nColIndices(UBound(data, 2)))
End Sub
Help functions to LeaveUniques
Function uniqueRowIndices(data, Optional ByVal colNum As Long = 1)
'Purpose: return data index numbers referring to uniques
'a) set late bound dictionary to memory
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'b) slice e.g. first data column (colNum = 1)
Dim colData
colData = Application.Index(data, 0, colNum)
'c) fill dictionary with uniques referring to first occurencies
Dim i As Long
For i = 1 To UBound(colData)
If Not dict.exists(dict(colData(i, 1))) Then dict(colData(i, 1)) = i
Next
'd) return 2-dim array of valid unique 1-based index numbers
uniqueRowIndices = Application.Transpose(dict.items)
End Function
Function nColIndices(ByVal n As Long)
'Purpose: return "flat" array of n column indices, e.g. for n = 3 ~> Array(1, 2, 3)
nColIndices = Application.Transpose(Evaluate("row(1:" & n & ")"))
End Function

Resources