Excel VBA dictionary- How to get get Item values of Duplicate Key in cells? - excel

Im trying to find way how to use Dictionary to delete duplicate values and concatenate items values in cells.
Code belowe is doing what i imagine but I can see it in immediate window (Debug.Print dict(People).
Item (ID) of duplicate values of dictionary Keys(People) are concatenate with comma but i dont know how to extract that Items to cell.
So idea for VBA to do is find duplicate value and concatenate ID values and delete duplicate.
Thank you!
Option Explicit
Sub DictionaryTest()
Dim dict As Scripting.Dictionary
Dim rowCount As Long
Dim People As String
Dim ID As Integer
Dim item As Variant
Set dict = New Scripting.Dictionary
rowCount = Cells(Rows.Count, "E").End(xlUp).Row
'Debug.Print rowCount
Do While rowCount > 1
People = Sheet2.Cells(rowCount, "E").Value
ID = Sheet2.Cells(rowCount, "D").Value
If dict.Exists(People) Then
'Sheet2.Rows(rowCount).EntireRow.Delete
Else
dict.Add People, ID
End If
rowCount = rowCount - 1
Loop
End Sub

Try this adapted code, please:
Sub DictionaryTest()
Dim dict As New Scripting.Dictionary
Dim rowCount As Long, i As Long
Dim People As String
Dim ID As Integer
Dim sh As Worksheet
Set sh = Sheet2
rowCount = sh.cells(Rows.count, "D").End(xlUp).Row
For i = 2 To rowCount
People = sh.cells(i, "D").Value
ID = sh.cells(i, "C").Value
If dict.Exists(People) Then
dict(People) = dict(People) & "," & ID
Else
dict.Add People, ID
End If
Next i
sh.Range("F2").Resize(dict.count).Value = WorksheetFunction.Transpose(dict.Items)
sh.Range("G2").Resize(dict.count).Value = WorksheetFunction.Transpose(dict.Keys)
End Sub

Related

VBA loop through column and store values in an array

I have my column B, starting from cell 2 (because of the header) containing codes of type String. I would like to get a list of these codes. However, these codes are repeated a number of times. So I would like to loop through my column B and add to my array of codes whenever a new one is encountered, if that makes sense.
Here is my code. How can this be done ? Thanks in advance.
Sub List()
Dim listCodes() As String
With Worksheets("My sheet)
nbr_lines = .Rows.Count
Dim i As Long
val_old = .Cells(2, 2).Value
listCodes(1) = val_old
For i = 2 To nbr_lines
val_new = .Cells(i + 1, 2).Value
While val_old = val_new
val_old = val_new
Wend
listCodes(i) = val_new
val_old = val_new
Next i
End With
End Sub
As mentioned in my comment, I'd suggest a dictionary. Drop the entire column into an array for speedy processing first, then throw it all in the dictionary:
Sub List()
Dim listCodes() As Variant
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim nbr_lines As Long
With Worksheets("My sheet")
'Get last used line and throw values in array;
nbr_lines = .Cells(.Rows.Count, 2).End(xlUp).Row
listCodes = .Range("B2:B" & nbr_lines).Value
'Loop array instead of cells for speed. Add all unique items into dictionary;
For Each el In listCodes
dict(el) = ""
Next
'Add the content of the dictionary to the sheet;
.Range("C2").Resize(dict.Count).Value = Application.Transpose(dict.Keys)
End With
End Sub
Note: This can also be achieved outside of VBA through easy formulae like the UNIQUE() function.
You can use dictionary approach. Below sub will copy only unique items to column D. Modify codes as your need.
Public Sub CopyUniqueOnly()
Dim i As Long
Dim currCell As Range, dict As Object
Set dict = CreateObject("Scripting.Dictionary")
With ThisWorkbook.Worksheets("Sheet1")
For Each currCell In .Range("B2", .Cells(.Rows.Count, 2).End(xlUp))
If Not dict.exists(currCell.Value) And Not IsEmpty(currCell) Then
dict.Add currCell.Value, currCell.Value
End If
Next currCell
End With
Range("D2").Resize(dict.Count) = Application.Transpose(dict.keys)
End Sub

Excel VBA Dictionary item concatenate

i need help with dictionary understanding so im trying with something simple. I have code that search and delete duplicate value.
I store dict Key as People and item as ID's. Idea is to loop to cell range with data, find duplicate values delete them but concatenate Item(ID's).
How can i get item from Dictionary to range cell with ID's and concatenate values? I wolud appreciate and help, link, tutorial, suggestion
Code so far:
Option Explicit
Sub DictionaryTest()
Dim dict As Scripting.Dictionary
Dim rowCount As Long
Dim People As String
Dim ID As Integer
Dim item As Variant
Set dict = New Scripting.Dictionary
rowCount = Cells(Rows.Count, "E").End(xlUp).Row
'Debug.Print rowCount
Do While rowCount > 1
People = Sheet2.Cells(rowCount, "E").Value
ID = Sheet2.Cells(rowCount, "D").Value
If dict.Exists(People) Then
'Sheet2.Rows(rowCount).EntireRow.Delete
Else
dict.Add People, ID
End If
rowCount = rowCount - 1
Loop
End Sub
Thank you!
Instead of storing the ID value in the dictionary, you can reference the ID cell and concatenate the values there.
Dim idCell As Range, r As Long
'...
'...
For r = rowCount to 2 Step - 1
People = Sheet2.Cells(rowCount, "E").Value
Set idCell = Sheet2.Cells(rowCount, "D")
If dict.Exists(People) Then
With dict(People) '<< first id cell...
.Value = .Value & ";" & IdCell.Value
End With
Sheet2.Rows(rowCount).EntireRow.Delete 'get id *before* delete ;-)
Else
dict.Add People, idCell 'reference first ID cell (the cell
' itself, not the cell value)
End If
Next r
Please see if this works for you.
Sub RemDupVal()
Dim t As Range, x As Range, z As Range
Set x = Range("A2:A7") 'ID
Set z = Range("B2:B7") 'Item
Set t = Cells(2, Cells(1, 16383).End(xlToLeft).Column + 1).Resize(x.Rows.Count)
t = x.Parent.Evaluate(x.Address & "&" & z.Address) 'assuming evaluate character limit is met
Union(x, t).Select
selection.RemoveDuplicates t.Column, xlNo
t.ClearContents: Cells(1, 1).Select
End Sub
I'm working on this code and update it a bit. I see that I Immediate window Items from duplicate dictionary are concatenate so code work exactly what I want but I don't know how I can get that value concatenate in cells. In dictionary keys are People and Item are ID
This is best result I have in many code testing.
Sub DictTest()
Dim dict As Scripting.Dictionary
Dim rowsCount As Long
Dim People As String, id As Integer
Set dict = New Scripting.Dictionary
rowsCount = Cells(Rows.Count, "D").End(xlUp).Row
People = Sheet2.Cells(rowsCount, "D").Value
Do While rowsCount > 1
People = Sheet2.Cells(rowsCount, "D").Value
id = Sheet2.Cells(rowsCount, "C")
'if duplicate value is found then concatenate Item value
If dict.Exists(People) Then
dict(People) = dict(People) & "," & " " & id
Debug.Print dict(People) '-> in immediate window shows concatenate Item values
Sheet2.Rows(rowsCount).EntireRow.Delete
Else
dict.Add People, id
End If
rowsCount = rowsCount - 1
Loop
End Sub

Convert Excel Array formula into VBA code

I have two set of range named as LIST_KEY and LIST_CAT. In Column A, user will add some data which will contain one of the one of the text from LIST_KEY. I would like to get corresponding Category list from LIST_CAT depends upon the Key value
I am using below VBA code to achieve this. This include a Array formula.
Sub match()
Dim ss As Workbook
Dim test As Worksheet
Set ss = Excel.Workbooks("test.xlsm")
Set test = ss.Worksheets("Sheet1")
For i = 2 To test.Cells(Rows.Count, "A").End(xlUp).Row
Cells(i, "B").FormulaArray = "=INDEX(LIST_CAT,MATCH(TRUE,ISNUMBER(SEARCH(LIST_KEY,RC[-1])),0))"
Cells(i, "B").Formula = Cells(i, "B").Value
Next i
End Sub
This code works perfect if there is less data to fetch. But in my original use case, I will have around 8000 rows. Due to this large number of columns excel will go to not responding state after 2-3 minutes.
Instead of adding Array formula to column B, Is there anyway to convert that into VBA to run this faster. Sorry, I am new to this VBA stuff and dont have much experience
Try the following code, which uses arrays instead of worksheet formulas...
Option Explicit
Sub GetCategories()
Dim sourceWorkbook As Workbook
Set sourceWorkbook = Workbooks("test.xlsm")
Dim sourceWorksheet As Worksheet
Set sourceWorksheet = sourceWorkbook.Worksheets("Sheet1")
Dim lookupArray As Variant
lookupArray = sourceWorkbook.Names("LIST_KEY").RefersToRange.Value
Dim returnArray As Variant
returnArray = sourceWorkbook.Names("LIST_CAT").RefersToRange.Value
Dim tableArray As Variant
Dim lastRow As Long
With sourceWorksheet
lastRow = .Cells(.Rows.Count, "a").End(xlUp).Row
tableArray = .Range("A2:B" & lastRow).Value
End With
Dim desc As String
Dim i As Long
Dim j As Long
For i = LBound(tableArray, 1) To UBound(tableArray, 1)
desc = tableArray(i, 1)
For j = LBound(lookupArray, 1) To UBound(lookupArray, 1)
If InStr(1, desc, lookupArray(j, 1), vbTextCompare) > 0 Then
tableArray(i, 2) = returnArray(j, 1)
Exit For
End If
Next j
Next i
sourceWorksheet.Range("B2").Resize(UBound(tableArray, 1), 1).Value = Application.Index(tableArray, 0, 2)
End Sub

VBA code for saving specific range of rows

Question regarding the code below. I need this randomizer to save the random entries that it created on a separated file without deleting previous entries that got saved, how should I proceed?
Private Sub CommandButton1_Click()
Dim lastRow As Long
Dim shAudit As Worksheet
Dim shData As Worksheet
Dim r As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim key As Variant
name = Range(A5, H9).Value
Set shAudit = ThisWorkbook.Sheets("Sheet1")
Set shData = ThisWorkbook.Sheets("Sheet2")
lastRow = shData.Range("A" & shData.Rows.Count).End(xlUp).Row
'Pick 5 random records with no repeats
Do Until dict.Count = 5
r = Application.WorksheetFunction.RandBetween(2, lastRow)
If Sheets("Sheet1").Range("A2") = Sheets("Sheet2").Cells(r, "G") Then
If Not dict.Exists(r) Then
dict.Add r, r
End If
End If
Loop
r = 0
For Each key In dict.Keys
shData.Range("A1:H1").Offset(key - 1, 0).Copy shAudit.Range("A5:H5").Offset(r, 0)
r = r + 1
Next key
End Sub
You can add this line just before End Sub. Change the sheet name to suit.
Worksheets("Sheet3").Range("A" & Rows.Count).End(xlUp)(2).Resize(dict.Count) = Application.Transpose(dict.keys)

Excel VBA Populate Listbox1 based on Listbox2 Selection

I am trying to figure out the proper code for populating a listbox based on a selection from a second listbox. I will explain my question the best I can. I have one worksheet with two columns populated like this.
(COLUMN A) (COLUMN B)
PART NUMBER: LOCATION:
PART A LOC1,LOC7,LOC12,LOC21
PART B LOC2,LOC8,LOC13,LOC22
PART C LOC6,LOC9,LOC18,LOC20
I want to be able to populate ListBox1 with the "PART NUMBER" column and when I click on "PART A" I get just a list of items for location from (Column B) in ListBox2. I hope this makes sense and someone can help me out. Thank you in advance.
To populate my ListBox:
Dim rngName As Range
Dim ws As Worksheet
Dim i As Integer
Set ws = Worksheets("Sheet2")
For i = 1 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row Step 1
If ws.Cells(i, 1).Value <> vbNullString Then Me.LstPartNum.AddItem ws.Cells(i, 1).Value
Next i
To Test populate and split by commas:
UserForm1.LstPartNum.List = Split("LOC1,LOC7,LOC12,LOC21", ",")
In the change event of the part number combobox do something like this.
Dim ws As Excel.Worksheet
Dim lRow As Long
Set ws = Worksheets("Sheet2")
lRow = 1
'Loop through the rows
Do While lRow <= ws.UsedRange.Rows.count
'Check if Column A has the value of the selected part number.
If ws.Range("A" & lRow).Value = LstPartNum.Text Then
UserForm1.LstLocation.Clear
'Load the locations
UserForm1.LstLocation.List = Split(ws.Range("B" & lRow).Value, ",")
Exit Do
End If
lRow = lRow + 1
Loop
If your UserForm1.LstPartNum.List = Split() does not work to load the list, here is code to loop the split array.
Dim szLocs() As String
Dim i as integer
szLocs= Split(ws.Range("B" & lRow).Value, ",")
i = 0
'Loop though each token
Do While i <= UBound(szPieces)
UserForm1.LstPartNum.Additem szPieces(i)
i = i + 1
Loop

Resources