Select a Value from Form ListBox and Show Value Associated - excel

I have a list of items and descriptions in column A. The first item is in the 5th row. Each item is followed by the item description.
It looks something like the following (different, but the same concept):
Apple
Red Fruit
Banana
Yellow Fruit
What I am trying to do is put these both into 2 arrays based on whether it's an item or the description.
I've done that here:
Option Explicit
Option Base 1
Sub main()
Dim rngList As Range
Dim strNetId As String
Dim strListArray() As String
Set rngList = Sheets("data").Range("A1").CurrentRegion
Call CreateArray(rngList, strListArray())
Call CreateArray2(rngList, strListArray())
End Sub
Sub CreateArray(rngIn As Range, strArray() As String)
Dim iCols As Integer
Dim iRows As Integer
Dim iRowsH As Integer
Dim i As Integer
Dim j As Integer
Dim Counter As Integer
Dim Counter2 As Integer
Dim Count2 As Integer
iRows = (rngIn.Rows.Count - 1)
iCols = 1
iRowsH = (rngIn.Rows.Count - 1) / 2
ReDim strArray(iRows, iCols)
Count2 = 3
Counter = 1
Do
If Count2 Mod 2 <> 0 Then
strArray(Counter, 1) = rngIn.Cells(Count2 + 2, 1)
Counter = Counter + 1
End If
Count2 = Count2 + 1
Loop Until Count2 > iRows
End Sub
Sub CreateArray2(rngIn2 As Range, strArray2() As String)
Dim iCols As Integer
Dim iRows As Integer
Dim iRowsH As Integer
Dim i As Integer
Dim j As Integer
Dim Counter As Integer
Dim Counter2 As Integer
Dim Count2 As Integer
iRows = (rngIn2.Rows.Count - 1)
iCols = 1
iRowsH = (rngIn2.Rows.Count - 1) / 2
ReDim strArray2(iRows, iCols)
Count2 = 3
Counter = 1
Do
If Count2 Mod 2 = 0 Then
strArray2(Counter, 1) = rngIn2.Cells(Count2 + 2, 1)
Counter = Counter + 1
End If
Count2 = Count2 + 1
Loop Until Count2 > iRows
End Sub
Where I'm running into a problem is getting my form to work. What I want to happen is you start the form and then click one of the items that will be populated in the ListBox. Then a text box will pull up the associated description. Here's what I have in my form's code, but I'm getting an error when you actually select the item from the form:
Option Base 0
Option Explicit
Dim strArray2()
Private Sub btnDone_Click()
Unload frmNetID
End Sub
Private Sub lstNetID_Click()
lblFirstName.Caption = strArray2(lstNetID.ListIndex + 2, 1)
End Sub
Private Sub UserForm_Initialize()
Dim rngList As Range
Dim strNetId As String
Dim strList() As String
Dim iR As Integer
With ThisWorkbook.Worksheets("data")
iR = .Range("A1").CurrentRegion.Rows.Count
Set rngList = .Range("A1:A" & iR) 'it assumes header row
Call CreateArray(rngList, strList())
End With
lstNetID.List() = strList()
End Sub
Where am I making the first mistake? I'm guessing it has something to do with the lblFirstName.Caption line of code.

You code can be simplified and more eficient, I think. Please, see how the necessary arrays can be a little differently built and used:
Private Sub testFillArrays()
Dim sh As Worksheet, arr As Variant, arrN As Variant, arrD As Variant
Dim n As Long, d As Long, i As Long, arrGlob() As Variant
Set sh = ActiveSheet 'you will use Sheets("data")
arr = sh.Range("A1").CurrentRegion.Value2 'base 1 array
ReDim arrN(0 To UBound(arr, 2), 0 To Int(UBound(arr, 1) / 2)) '(0 based array)
ReDim arrD(0 To UBound(arr, 2), 0 To Int(UBound(arr, 1) / 2))
For i = 2 To UBound(arr)
If i Mod 2 = 0 Then
arrN(0, n) = arr(i, 1): n = n + 1 ' fruit names array
Else
arrD(0, d) = arr(i, 1): d = d + 1 ' fruit colors array
End If
Next i
ReDim Preserve arrN(0 To 1, 0 To n - 1) 'clear the last empty element
ReDim Preserve arrD(0 To 1, 0 To d - 1)
'arrN is the array to be load in the list box.
arrGlob = Array(arrN, arrD) 'define the array of arrays
i = lstNetID.ListIndex
Debug.Print arrGlob(0)(0, i), arrGlob(1)(0, i) 'and press Ctrl + G to see the result...
End Sub

Related

Replace and save remaining string in an array

I want to remove predefined parts of the strings in the following table and save the values in an array. For some reason I get an error stating that I'm outside of the index. The lengths of the strings in the table can vary.
Sub New_1()
Dim i, j, k As Integer
Dim Endings As Variant
k = 0
Endings = Array("/A", "/BB", "/CCC", "/DDDD", "/EEEEE")
Dim ArrayValues() As Variant
With Worksheets("table1")
Dim lastRow As Long: lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
ReDim ArrayValues(lastRow)
For i = lastRow To 1 Step -1
For j = 0 To UBound(Endings)
ArrayValues(k) = Replace(.Range("A" & i), Endings(j), "")
k = k + 1
Next j
Next i
End With
End Sub
You're getting out of bounds because your ArrValues is filled up after not even 3 iterations of your "i" since you're adding up your k every j iterations
If you want an array of the cleaned up cells do this instead:
Sub New_1()
Dim i As Integer, j As Integer, k As Integer
Dim Endings As Variant
Dim ArrayValues() As Variant
Dim lastRow As Long
Endings = Array("/A", "/BB", "/CCC", "/DDDD", "/EEEEE")
With Worksheets("Blad6")
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
ReDim ArrayValues(1 To lastRow) 'Then you don't have an empty ArrayValues(0)
For i = lastRow To 1 Step -1
For j = 0 To UBound(Endings)
If j = 0 Then
ArrayValues(i) = Replace(.Range("A" & i), Endings(j), "")
Else
ArrayValues(i) = Replace(ArrayValues(i), Endings(j), "")
End If
Next j
Next i
'Use Array here
End With
End Sub
If your intent is to create an array in which everything after the / is removed, this might be simpler, using the Split function; and also faster by storing the data to be split in a VBA array, in iterating through that array instead of the worksheet cells.
Option Explicit
Sub New_1()
'in VBA, Long is marginally more efficient than Integer
Dim k As Long, v As Variant
Dim dataArr As Variant
Dim ArrayValues() As Variant
With Worksheets("SHEET7")
'faster to loop through VBA array than worksheet cells
'Note that this will be a 2D array with dimensions starting at 1, not 0
dataArr = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))
End With
'This might be simpler
ReDim ArrayValues(1 To UBound(dataArr, 1))
k = 0
For Each v In dataArr
k = k + 1
ArrayValues(k) = Split(v, "/")(0)
Next v
End Sub

Running Total Excel or VBA functionReset Based on Cell value

Hi I have a column of 0's and 1's I want to create a running total of the non 0 values un-till it reaches a cell value of 0. Once it hits zero it should, return an empty cell, reset to 0, and begin again from 1 at the next cell value of 1.
Any help would be appreciated, including what I might want to look at to help.
Editing with current solution:
Ive found this solution that works, how would I go about making this a function instead of using this Sub()?
Sub test()
Dim value As Integer
value = 0
For i = 1 To Range("Table2").Rows.Count
If ThisWorkbook.Worksheets("Sheet1").Range("Table2[Current Col]").Cells(i) = 0 Then
value = 0
Range("Table2[New Column]")(i) = ""
ElseIf ThisWorkbook.Worksheets("Sheet1").Range("Table2[Current Col]").Cells(i) = 1 Then
value = value + 1
Range("Table2[New Column]")(i) = value
End If
Next i
End Sub
Incrementing Groups
Use variables to avoid long unreadable lines.
Option Explicit
Sub test()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim srg As Range: Set srg = ws.Range("Table2[Current Col]")
Dim drg As Range: Set drg = ws.Range("Table2[New Col]")
Dim sValue As Variant
Dim dValue As Variant
Dim iValue As Long
Dim i As Long
For i = 1 To srg.Cells.Count
' Read from source cell into a variable ('sValue').
sValue = srg.Cells(i).Value
' Test and write result to a variable ('dValue').
If IsNumeric(sValue) Then
If sValue = 1 Then
iValue = iValue + 1
dValue = iValue
End If
Else
iValue = 0
dValue = Empty
End If
' Write from the variable ('dValue') to the destination cell.
drg.Cells(i).Value = dValue
Next i
End Sub
As a UDF:
Function CountUp(rng As Range)
Dim arr, arrOut(), v As Long, i As Long
arr = rng.Columns(1).value
ReDim arrOut(1 To UBound(arr, 1), 1 To UBound(arr, 2))
v = 0
For i = 1 To UBound(arr, 1)
v = IIf(arr(i, 1) = 1, v + 1, 0)
arrOut(i, 1) = v
Next i
CountUp = arrOut
End Function
If your Excel version has the "autospill" feature then you can enter it as a normal function: if not then you need to select the whole output range and enter the formula using Ctrl+Shift+Enter

Why when reading my array onto cells in VBA does it repeat every row?

My code simply reads:
Board = Array(1,2,3,4,5,6,7,8,9)
Range("A1:C3") = Board
But when executed repeats 1, 2, 3 across the rows A1 to C1, A2 to C2 and A3 to C3. How do I fix this?
Use a 2D array:
Dim Board(1 To 3, 1 To 3) As Variant 'or As Long
Dim i As Long, j As Long
For i = LBound(Board, 1) To UBound(Board, 1)
For j = LBound(Board, 2) To UBound(Board, 2)
Dim counter As Long
counter = counter + 1
Board(i, j) = counter
Next
Next
Range("A1:C3").Value = Board
Flexible way to slice "flat" array data into range
I assume that Pingu wants to repart a flat array onto the example range.
Furthermore I've been spurred on to this approach by #ScottCraner citing
"You set up a 1D array, that is one row; you will need to make the array the shape you want before trying to post it to the cells.
VBA will not automatically set the array to the shape."
The following function Sliced()` not only tries to this profiting from
a) some evalutions to get the numeric items order,
b) the advanced features of the `Application.Index() function to allow rearranging,
but also to allow a fully flexibilized execution with any column number needed:
Function sliced(arr, Optional ByVal cols As Long = 1)
'Purpose: slice 1-dim array into given number of columns and flexible number of rows
'a) adjust 1-based item numbers into 2-dim array
Dim tmp: tmp = Join(Application.Transpose(Evaluate("row(1:" & cols & ")")), ",")
Dim c: c = Evaluate("row(1:" & UBound(arr) \ cols + 1 & ")*" & cols & "+{" & tmp & "}-" & cols)
'b) return 2dim array sliced into given number of columns and flexible number of rows
sliced = Application.Index(arr, 1, c)
End Function
Example Call
Sub ExampleCall()
'[0]Given input
Dim board: board = Array(10, 20, 30, 40, "50", 60, 70, 80, 90)
Const cols As Long = 3 ' << intended number of columns
'[1]get results array
Dim results: results = sliced(board, cols)
'[2]write to any target
Sheet1.Range("A1").Resize(UBound(results), cols) = results
End Sub
Fill Range with Array
Only run the first procedure which calls the second which calls the third.
Note that a range can be 'filled' by rows and by columns.
Change the values in the first procedure to understand the full potential.
The Code
Option Explicit
Sub TESTfillRangeWithArray()
Dim Board As Variant: Board = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
Dim rng As Range: Set rng = Range("A1:C3")
' Either...
fillRangeWithArray rng, Board ' By Rows
' ...or
'fillRangeWithArray rng, Board, True ' By Columns
End Sub
Sub fillRangeWithArray( _
ByRef rng As Range, _
OneD As Variant, _
Optional ByVal ByColumns As Boolean = False)
' Indexes
Dim FirstIndex As Long: FirstIndex = LBound(OneD)
Dim LastIndex As Long: LastIndex = UBound(OneD)
Dim n As Long: n = FirstIndex - 1
' Limits
Dim rCount As Long: rCount = rng.Rows.Count
Dim cCount As Long: cCount = rng.Columns.Count
' Data Array
Dim Data As Variant
If rCount > 1 Or cCount > 1 Then
ReDim Data(1 To rCount, 1 To cCount)
Else
ReDim Data(1 To 1, 1 To 1)
End If
' Counters
Dim i As Long
Dim j As Long
' Loop
If Not ByColumns Then
For i = 1 To rCount
For j = 1 To cCount
determineIndex n, FirstIndex, LastIndex
Data(i, j) = OneD(n)
Next j
Next i
Else
For j = 1 To cCount
For i = 1 To rCount
determineIndex n, FirstIndex, LastIndex
Data(i, j) = OneD(n)
Next i
Next j
End If
' Result
rng.Value = Data
End Sub
Private Sub determineIndex( _
ByRef CurrentIndex As Long, _
ByVal FirstIndex As Long, _
ByVal LastIndex As Long)
' Indexes
If CurrentIndex < LastIndex Then
CurrentIndex = CurrentIndex + 1
Else
CurrentIndex = FirstIndex
End If
End Sub

Write array to the worksheet and repeat it n times

I am working on the code where I want to write 2 arrays (assigned in 'Input sheet) to 'Output' sheet n times, i.e. specifically 2 times in the loop. I want to use arrays because the range of the ids and its names can change (it can be much more).
To start with a simple example (with a small amount of data), the arrays are assigned acc. to data in 'Input' sheet:
These 2 arrays should be written to 'Output' sheet n times i.e.; They should be written once and then again in the loop i.e. 2 times. I want to do it in the loop to give it the flexibility of writing in the future e.g. 3, 4, n times. In this example, I do it 2 times. Before each written array, there should be written a heading 'Title' and at the end of the written array should written text 'Total', therefore this is my desired outcome:
My code works only to write the 2 arrays for the first time but it does not write these 2 arrays for 2nd time. Instead, I am getting something else which is wrong:
This is my code:
Sub Write1()
Dim r As Long
Dim c As Long
Dim Start_Row As Long
Dim End_Row As Long
Dim main As Integer
Dim lngRowCount As Long
Dim w_Output As Worksheet
Dim w1 As Worksheet
Dim intLastRow As Integer
Const RowStart As Integer = 3
Const ColumnID As Integer = 1
Const Column_Desc As Integer = 3
Dim arrID() As Variant
Dim arrDesc() As Variant
With ThisWorkbook
Set w1 = .Sheets("Input")
Set w_Output = .Sheets("Output")
End With
'***********************************
'arrays
With w1
intLastRow = .Cells(Rows.Count, 1).End(xlUp).Row
'IntLastCol = .Cells(4, Columns.Count).End(xlToLeft).Column
arrID = .Range(.Cells(RowStart, ColumnID), .Cells(intLastRow, ColumnID))
arrDesc = .Range(.Cells(RowStart, Column_Desc), .Cells(intLastRow, Column_Desc))
'******************************************
main = 1
End_Row = 2 'this is the 2nd iteration to write arrays
For Start_Row = 1 To End_Row
w_Output.Cells(main, 3) = "Title"
main = main + 1
For r = 1 To UBound(arrID, 1)
If Len(arrID(r, 1)) > 0 Then
'Write
w_Output.Cells(r + 1, 3) = arrID(r, 1)
w_Output.Cells(r + 1, 4) = arrDesc(r, 1)
End If
main = main + 1
w_Output.Cells(main, 3) = "Total "
Next r
main = main + 4
Next Start_Row
End With
MsgBox "Done", vbInformation
End Sub
Does anybody know what I do wrong in my loop to make it work?
I have figured it out, it turns out the I was simply supposed to use 'main' as the row to write to the sheet and not 'r' which is used for the arrays - this is part of the code where arrays are written to the sheet.
Sub Write1()
Dim r As Long
Dim c As Long
Dim d As Long
Dim Start_Row As Long
Dim End_Row As Long
Dim main As Integer
Dim lngRowCount As Long
Dim w_Output As Worksheet
Dim w1 As Worksheet
Dim intLastRow As Integer
Dim IntLastCol As Integer
Const RowStart As Integer = 3
Const ColumnID As Integer = 1
Const Column_Desc As Integer = 3
Dim arrID() As Variant
Dim arrDesc() As Variant
With ThisWorkbook
Set w1 = .Sheets("Input")
Set w_Output = .Sheets("Output")
End With
'***********************************
'arrays
With w1
intLastRow = .Cells(Rows.Count, 1).End(xlUp).Row
arrID = .Range(.Cells(RowStart, ColumnID), .Cells(intLastRow, ColumnID))
arrDesc = .Range(.Cells(RowStart, Column_Desc), .Cells(intLastRow, Column_Desc))
'******************************************
main = 1
End_Row = 2
For Start_Row = 1 To End_Row
w_Output.Cells(main, 3) = "Title"
main = main + 1
For r = 1 To UBound(arrID, 1)
If Len(arrID(r, 1)) > 0 Then
'Write
w_Output.Cells(main, 3) = arrID(r, 1)
w_Output.Cells(main, 4) = arrDesc(r, 1)
End If
main = main + 1
Next r
w_Output.Cells(main, 3) = "Total "
main = main + 4
Next Start_Row
End With
MsgBox "Done", vbInformation
End Sub
It works perfectly.

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