I am trying to use a dictionary to create array of unique items from a column range
The column cells are text (titles)
I know very little about dictionaries, trying to learn something new
I get an array filled with 1's
Thanks
Sub GetUniques()
Dim d As Object, k, a As Variant, c As Variant, i As Long, j As Long, LR As Long
Set d = CreateObject("Scripting.Dictionary")
LR = Cells(Rows.Count, 1).End(xlUp).Row
c = Range("D2:D" & LR).Value2
For i = 1 To UBound(c)
d(c(i, 1)) = 1
Next i
ReDim a(1 To d.Count)
j = 1
For Each k In d.keys
a(j) = k
j = j + 1
Next k
'See what the first item of the array is
MsgBox a(1)
End Sub
I use collection to create unique items. Here is an example
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long
Dim Col As New Collection, itm As Variant
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To lRow
On Error Resume Next
Col.Add .Range("A" & i).Value, CStr(.Range("A" & i).Value)
On Error GoTo 0
Next i
End With
For Each itm In Col
Debug.Print itm
Next
End Sub
EDIT
And if you want to convert that collection to array then you can add this code
Dim MyAr() As Variant
ReDim MyAr(0 To (Col.Count - 1))
For i = 1 To Col.Count
MyAr(i - 1) = Col.Item(i)
Next
Followup from comments
Is this what you are trying?
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long
Dim Col As New Collection, itm As Variant
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To lRow
On Error Resume Next
Col.Add .Range("A" & i).Value, CStr(.Range("A" & i).Value)
On Error GoTo 0
Next i
End With
Dim MyAr() As Variant
ReDim MyAr(0 To (Col.Count - 1))
For i = 1 To Col.Count
MyAr(i - 1) = Col.Item(i)
Next
ws.Range("K1").Resize(UBound(MyAr), 1) = Application.Transpose(MyAr)
End Sub
Note: I see that your query is solved but If I was you, I would use the inbuilt RemoveDuplicates which is much more faster and shorter than the code above
Columns(1).Copy Columns(11)
Columns(11).RemoveDuplicates Columns:=1, Header:=xlNo
Related
with the given code I am trying hard incorporate the Filldown approach until the last row but at present whatever I do only fills row number 1:
Sub FillDownApproach()
Dim destinationWs As Worksheet
Dim destinationLastRow As Long
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
RetVal = destinationWs.Evaluate("INDEX('MyData'!$E:$E,MATCH(1,($A2='MyData'!$B:$B)*(""MyItem""='MyData'!$D:$D),0))")
destinationWs.Range("C2").Value = RetVal
destinationWs.Range("C3: " & "C" & destinationLastRow).FillDown
End Sub
Any suggestion that could point towards the right direction.
Thanks
You cannot do what you want without looping. And Looping ranges is slow.
Instead load Variant arrays and loop them.
Sub FillDownApproach()
Dim destinationWs As Worksheet
Set destinationWs = ThisWorkbook.Worksheets("Main Board")
Dim destinationLastRow As Long
destinationLastRow = destinationWs.Range("A" & Rows.Count).End(xlUp).Row
Dim lkpArr As Variant
lkpArr = destinationWs.Range("A2:A" & destinationLastRow).Value
With Worksheets("MyData")
Dim retval As Variant
retval = Intersect(.Range("E:E"), .UsedRange)
Dim mtch As Variant
mtch = Intersect(.Range("B:D"), .UsedRange)
End With
Dim outArr As Variant
ReDim outArr(1 To UBound(lkpArr, 1), 1 To 1)
Dim i As Long
For i = 1 To UBound(lkpArr, 1)
Dim j As Long
For j = 1 To UBound(retval, 1)
If mtch(j, 3) = "MyItem" Then
If mtch(j, 1) = lkpArr(i, 1) Then
outArr(i, 1) = retval(j, 1)
Exit For
End If
End If
Next j
Next i
destinationWs.Range("C2").Resize(UBound(outArr, 1), 1).Value = outArr
End Sub
I need some help with comparing values from one column to another and delating it.
so far I have this:
Sub DelateDuplicates()
delArray = Sheets("Save").Range("B1:B") ' saved values
toDelate = Sheets("Validation").Range("B2:B").Value ' values to be checked and delated
lastRow = toDelate.Range("B1000").End(xlUp).Row ' last row
Firstrow = toDelate.Range("B2").End(xlDown).Row ' First row
Dim i As Long
For Lrow = lastRow To Firstrow Step -1
With Worksheets("Validation").Cells(Lrow, "A")
For i = 0 To UBound(delArray) ' arrays are indexed from zero
If Not IsError(.Value) Then
If .Value = delArray(i) Then
.EntireRow.Delete
Exit For
End If
End If
Next
End With
Next Lrow
End Sub
And I do have an error.
"1004 "Application-defined or Object-defined error" "
I have spent 2 days trying to figure it out so far no luck.
Any help will be appreciated.
I modified your code little bit. You can define your first rows and last row the want you want, I have kept it simple for the sake of concept
Option Explicit
Sub DelateDuplicates()
Dim Lrow As Long
Dim delarray()
With Worksheets("Save")
delarray = .Range("B1:B" & .Cells(.Rows.Count, "B").End(xlUp).Row).Value
End With
Dim i As Long
Dim lastrow As Long
Dim firstrow As Long
firstrow = 1
With Worksheets("Validation")
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Lrow = lastrow To firstrow Step -1
For i = 1 To UBound(delarray)
If Not IsError(.Cells(Lrow, "A").Value) Then
If .Cells(Lrow, "A").Value = delarray(i, 1) Then
.Cells(Lrow, "A").EntireRow.Delete
Exit For
End If
End If
Next i
Next Lrow
End With
End Sub
You can avoid loops within loops by using a Dictionary Object
Option Explicit
Sub DeleteDuplicates()
Dim wsSave As Worksheet, wsValid As Worksheet
Dim iLastRow As Long, iFirstRow As Long, i As Long, n As Long
Dim dict As Object, key, cell As Range
With ThisWorkbook
Set wsSave = .Sheets("Save")
Set wsValid = Sheets("Validation")
End With
Set dict = CreateObject("Scripting.Dictionary")
' get values to delete from Column B
For Each cell In wsSave.Range("B1", wsSave.Cells(Rows.Count, "B").End(xlUp))
key = Trim(cell)
If Len(key) > 0 Then
dict(key) = cell.Row
End If
Next
' scan Validation sheet and delete matching from Save
With wsValid
iFirstRow = .Cells(2, "B").End(xlDown).Row
iLastRow = .Cells(Rows.Count, "B").End(xlUp).Row
For i = iLastRow To iFirstRow Step -1
key = .Cells(i, "A")
If dict.exists(key) Then
.Rows(i).Delete
n = n + 1
End If
Next
End With
' resutl
MsgBox n & " rows deleted between row " & _
iFirstRow & " and " & iLastRow, vbInformation
End Sub
I'm trying to calculate the Average value of multiple ranges as shown in attached Fig.
Conditions -
It should match the cell value of column "L" and "M" with a range of column "A" and Make a range (e.g 322810 to 324900) to calculate the average of column B values which are against the specific range (e.g 322810 to 324900).
I've been able to write the following code but it obviously not working.
Dim lastrow As Long
Dim i As Long, j As Long
With Worksheets("Source")
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lastrow + 1 'loop whole range (column C)
If .Cells(i, "L") = .Range("A").Value Then 'If column L cell value match with any cell of Range "A"
For j = i To lastrow 'Loop "group" range.
If .Cells(j, "M") = .Range("A").Value Then ' (end of small group range) then apply formula
.Cells(i, "N").Formula = "=AVERAGE(B" & i & ":B" & j & ")" 'AVG
Exit For
End If
Next j
End If
Next I
End With
All kind of help will be appreciated (Formula or VBA Code)
Yes, BigBen is right. This is the way. The Formula in my example is
=AVERAGEIFS($B$3:$B$16,$A$3:$A$16,">="&L4,$A$3:$A$16,"<="&M4)
Try,
Sub test()
Dim Lastrow As Long
Dim i As Long, j As Long
Dim r As Long
Dim mPoint As Long
Dim Ws As Worksheet
Dim vDB, vR()
Dim rngStart As Range, rngEnd As Range
Dim rngDB As Range
Set Ws = Worksheets("Source")
With Ws
Lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
vDB = .Range("L3", .Range("m" & .Rows.Count).End(xlUp))
r = UBound(vDB, 1)
ReDim vR(1 To r, 1 To 1)
For i = 1 To r
For k = 1 To Lastrow
If .Range("a1").Cells(k) = vDB(i, 1) Then
Set rngStart = .Range("a1").Cells(k)
mPoint = rngStart.Row
Exit For
End If
Next k
If rngStart Is Nothing Then
Else
For k = mPoint To Lastrow
If .Range("a1").Cells(k) = vDB(i, 2) Then
Set rngEnd = .Range("a1").Cells(k)
Exit For
End If
Next k
End If
If rngStart Is Nothing Or rngEnd Is Nothing Then
Else
Set rngDB = .Range(rngStart, rngEnd).Offset(, 1)
Debug.Print rngDB.Address
vR(i, 1) = WorksheetFunction.Average(rngDB)
End If
Set rngStart = Nothing
Set rngEnd = Nothing
Next i
.Range("n3").Resize(r) = vR
End With
End Sub
I have autofiltered a worksheet and am trying to establish the unique values within the filtered data. I feel like I have the correct approach, but the my results only show 2 of the possible 8 unique values.
Private Sub GetAllCampusDomains(DomainCol As Collection)
Dim data(), dict As Object, r As Long, i%, lastrow As Long
Set dict = CreateObject("Scripting.Dictionary")
'Clear the previous filter
shtData.ShowAllData
'Filter the data
shtData.Range("A:Y").AutoFilter Field:=6, Criteria1:=shtSetup.Range("CampusName") 'SchoolName
shtData.Range("A:Y").AutoFilter Field:=9, Criteria1:="DomainPerformance" 'ColI
'Inspect the visible cells in ColP
lastrow = shtData.Cells(shtData.Rows.Count, "P").End(xlUp).row
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
data = WorksheetFunction.Transpose(dict.keys())
'Walk through the unique values
For i = 1 To UBound(data)
Debug.Print data(i, 1)
'DomainCol.Add data(i, 1)
Next i
End Sub
The error seems to have to do with this line:
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
This call only seems to create a 90x1 sized array, when it should be much bigger.
I greatly appreciate your help!
Josh
Non-Contiguous Column Range to Jagged Array
Instead of...
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
...use the following...
Private Sub GetAllCampusDomains(DomainCol As Collection)
'...
Dim rng As Range
Set rng = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
getNonContiguousColumn Data, rng
'Find the unique values
Dim j As Long
For j = 0 To UBound(Data)
For r = 1 To UBound(Data(j))
dict(Data(j)(r, 1)) = Empty
Next r
Next j
'...
End Sub
...backed up by the following:
Sub getNonContiguousColumn(ByRef Data As Variant, _
NonContiguousColumnRange As Range, _
Optional FirstIndex As Long = 0)
Dim j As Long
j = FirstIndex - 1
ReDim Data(FirstIndex To NonContiguousColumnRange.Areas.Count + j)
Dim ar As Range
Dim OneCell As Variant
ReDim OneCell(1 To 1, 1 To 1)
For Each ar In NonContiguousColumnRange.Areas
j = j + 1
If ar.Cells.Count > 1 Then
Data(j) = ar.Value
Else
OneCell(1, 1) = ar.Value
Data(j) = OneCell
End If
Next ar
End Sub
Test the previous Sub with something like the following:
Sub testGetNCC()
Const rngAddr As String = "A2:A20"
Dim Data As Variant
Dim rng As Range
Set rng = Range(rngAddr).SpecialCells(xlCellTypeVisible)
getNonContiguousColumn Data, rng
Dim j As Long, i As Long
For j = 0 To UBound(Data)
For i = 1 To UBound(Data(j))
Debug.Print Data(j)(i, 1)
Next i
Next j
End Sub
Please, replace this piece of code:
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
with the next one:
Dim rng As Range, C As Range
Set rng = shtData.Range("P2:P" & lastRow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For Each C In rng.cells
dict(C.Value) = Empty
Next
Your initial code iterates between the first area range cells.
The second one will iterate between all visible range cells...
I've written a near-working script to search for a list of words in column B within a larger list in column A.
Sub QualifierArray()
Sub QualifierArray()
Dim List As Worksheet
Set List = Sheets("List")
Dim lastRow As Long
lastRow = (List.Cells(Rows.Count, 1).End(xlUp).Row) 'removed +1
Dim listColumn As Variant
listColumn = List.Range("A1:A" & lastRow)
Dim outputArray As Variant
Dim intQualifier As Long
Dim lastQualifier As Range
ReDim outputArray(1 To lastRow)
Dim i As Long
Dim j As Long
Dim index As Long
index = 1
intQualifier = Range("B" & Rows.Count).End(xlUp).Row
For j = 1 To intQualifier
For i = 1 To lastRow
Set rngQualifier = Range("B" & j)
If InStr(listColumn(i, 1), rngQualifier) > 0 Or InStr(listColumn(i, 1), "[") > 0 Then 'changed = to >
outputArray(index) = listColumn(i, 1)
index = index + 1
End If
Next
Next
End Sub
However, I'm getting a "subscript out of range" for the outputArray. It seems that index has increased to be more than lastRow, which is causing the error. I've tried a variety of fixes, like putting an extra clause like is not empty but to no avail. Does anyone have any suggestions as to what's causing the error? One clue is that removing the Or InStr(listColumn(i, 1), "[") = 0 part` lets the code perfectly (without this clause, of course). Am I getting close to a solution? It feels as if it's not far from here....
Thanks in advance!
try with below code
Sub QualifierArray()
Dim List As Worksheet
Set List = Sheets("List")
Dim lastRow As Long
lastRow = (List.Cells(Rows.Count, 1).End(xlUp).Row) 'removed +1
Dim listColumn As Variant
listColumn = List.Range("A1:A" & lastRow)
Dim outputArray As Variant
Dim intQualifier As Long
Dim lastQualifier As Range
ReDim outputArray(1 To lastRow)
Dim i As Long
Dim j As Long
Dim index As Long
index = 1
intQualifier = Range("B" & Rows.Count).End(xlUp).Row
For j = 1 To intQualifier
For i = 1 To lastRow
Set rngQualifier = Range("B" & j)
If InStr(listColumn(i, 1), rngQualifier) > 0 Or InStr(listColumn(i, 1), "[") > 0 Then 'changed = to >
outputArray(index) = listColumn(i, 1)
index = index + 1
End If
Next
Next
End Sub
Note: Changes made marked in comment