Remove Listbox item if match not found in VBA - vba

I am writing vba code that will search all listbox items against a entire column in a sheet.
If listbox item not found in Excel sheet column, i want to delete the item from list. I tried few codes, its showing some error as "Could not get list property, Invalid property array index". Below is my code i am using currently.
Private Sub CommandButton1_Click()
Dim itemExistResults As Boolean
Dim myarray()
Dim intItem As Long
myarray = Application.Transpose(Sheet1.Range("a2:a1000"))
For intItem = 0 To ListBox1.ListCount - 1
If IsInArray(ListBox1.List(intItem), myarray) Then
Else
ListBox1.RemoveItem intItem
End If
Next
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = UBound(Filter(arr, stringToBeFound)) > -1
End Function
Any idea where i am wrong in this code.

You should iterate from the last item of list to the first, because removing items changes their indexation.
Try to change your loop like that:
For intItem = ListBox1.ListCount - 1 To 0 Step -1
If IsInArray(ListBox1.List(intItem), myarray) Then
Else
ListBox1.RemoveItem intItem
End If
Next
I have a tip for you connected with your task, but not exactly with the error described in question.
For this type of task you should use object of Dictionary type instead of iterating through array - it would be much more effective.
I have modified your code to use dictionary. Check it and compare the time each of those solutions need to complete this task - the one with dictionary should be much faster. If you have any questions regarding this code, let me know in comments.
Private Sub CommandButton1_Click()
Dim myArray As Variant
Dim intItem As Long
Dim dict As Object
Dim i As Long
Dim value As Variant
'--- [Loading data into dictionary] ------------------------------------
Set dict = VBA.CreateObject("Scripting.Dictionary")
myArray = Sheet1.Range("A2:A1000")
'Iterate through all the items in array and load them into dictionary.
For i = LBound(myArray) To UBound(myArray)
value = myArray(i, 1)
If Not IsEmpty(value) Then
If Not dict.exists(value) Then
Call dict.Add(value, 0)
End If
End If
Next i
'-----------------------------------------------------------------------
'--- [Comparing ListBox with dictionary] -------------------------------
With ListBox1
For intItem = .ListCount - 1 To 0 Step -1
value = .List(intItem)
If Not dict.exists(value) Then
.RemoveItem intItem
End If
Next
End With
'-----------------------------------------------------------------------
End Sub

Related

2 Listboxes into 1 and then delete matching values VBA

I want to have 2 listboxes, 1 with a bunch of values and one with another bunch of values, I want to add them to a 3rd listbox and then delete all of the matching values,
here is my code i have got so far,
For i = 0 To (ListBox1.ListCount - 1)
ListBox3.AddItem (ListBox1.List(i))
Next
Dim qstring As String
For i = 0 To (ListBox2.ListCount - 1)
qstring = ListBox1.List(i)
With Me.ListBox3
'Loop through combobox
For b = 0 To .ListCount - 1
If .List(b) = qstring Then
strFound = True
Exit For
End If
Next b
'Check if we should add item
If Not strFound Then .AddItem (qstring)
End With
Next
Revised, Thank you for your help sir, I am now wondering why I am receiving this error, Thank you!
Error
You can use a Scripting.Dictionary object which allows unique Keys. You can check if an item exist using the .Exists method.
Sub Whatever()
Dim obj As Object
Set obj = CreateObject("Scripting.Dictionary")
'1st ListBox
For i = 0 To ListBox1.ListCount - 1
If Not obj.Exists(CStr(ListBox1.List(i))) Then
obj.Add CStr(ListBox1.List(i)), vbNullString
End If
Next
'2nd ListBox
For i = 0 To ListBox2.ListCount - 1
If Not obj.Exists(CStr(ListBox2.List(i))) Then
obj.Add ListBox2.List(i), vbNullString
End If
Next
'add unique list to 3rd ListBox
Dim Key As Variant
For Each Key In obj.Keys
ListBox3.AddItem Key
Next Key
End Sub
Edit:
Credit to #Nathan_Sav for pointing this out. No need to loop to fill the 3rd ListBox.
ListBox3.List = obj.Keys()

How to update values in VBA dictionary

StackOverflow,
The below subroutine is intended to:
take a dictionary (ByRef), with value types = double, OR
take a dictionary of dictionaries (ByRef), with sub-dictionary value types = double, and
apply the calculation "ApproximateGeometricReturn" to each value within the dictionary.
While the code successfully runs, it fails to apply the calculation to the each value in the dictionary passed as an argument (ByRef).
Please suggest where I may have gone wrong. I have also attempted to write this as a recursive subroutine without success.
Private Sub ApproxiamteGeometricReturns(ByRef LogReturnDictionary As Variant)
For Each Item In LogReturnDictionary.Items
If TypeName(Item) = "Double()" Then
For Each i In Item
i = ApproximateGeometricReturn(i)
Next
Else
Item = ApproximateGeometricReturn(Item)
End If
Next
End Sub
Any suggestions will be warmly received. Thanks.
Private Sub ApproxiamteGeometricReturns(ByRef LogReturnDictionary As Variant)
For Each keyName In LogReturnDictionary.Keys
If TypeName(LogReturnDictionary(keyName)) = "Double()" Then
Dim arr As Variant: arr = LogReturnDictionary(keyName)
Dim index As Integer
For index = LBound(arr) To UBound(arr)
arr(index) = ApproximateGeometricReturn(arr(index))
Next
LogReturnDictionary(keyName) = arr
Else
LogReturnDictionary(keyName) = ApproximateGeometricReturn(LogReturnDictionary(keyName))
End If
Next
End Sub

Why ListBox doesn't have a FindString method in Excel-VBA?

Trying to search on a ListBox. Specifically, I want to look at an array of items from the Cell, and for each one that matches an entry in the ListBox, I want it to select that List.
I copy-pasted some code that was supposed to let me find a string, but it keeps telling me:
Compile Error: Method or Data Member not found.
Any suggestions?
Relevant Code:
Public local_Target As Range
' local_Target is assigned in the sheet function to pass it here
Private Sub Network_ListBox_Enter()
' Get data in cell (if any)
Dim current_data As String
Dim entries() As String
current_data = local_Target.Value
If current_data = "" Then
Exit Sub
Else
entries = Split(current_data, vbNewLine)
End If
For Each Item In entries
FindMyString Item
Next Item
End Sub
Private Sub UserForm_Terminate()
Dim index As Integer
Dim result As String
' Iterate through the listbox and create the result, then assign to
' Target.value
For index = 0 To Network_ListBox.ListCount - 1
If Network_ListBox.Selected(index) Then
' stuff
If result = "" Then
result = Network_ListBox.List(index)
' ElseIf index = Network_ListBox.ListCount - 1 Then
' result = result + Network_ListBox.List(index)
Else
result = result + vbNewLine + Network_ListBox.List(index)
End If
End If
Next index
local_Target.Value = result
End Sub
Sub FindMyString(ByVal searchString As String)
' Ensure we have a proper string to search for.
If searchString <> "" Then
' Find the item in the list and store the index to the item.
Dim index As Integer
index = Me.Network_ListBox.FindString(searchString)
' Determine if a valid index is returned. Select the item if it is valid.
If index <> -1 Then
Network_ListBox.SetSelected index, True
'Else
' MessageBox.Show ("The search string did not match any items in the ListBox")
End If
End If
End Sub
I checked Intellisense and I don't think that Method is supported in VBA. Other documentations I've found refers to .Net Framework only as well. So maybe, it is not really supported in VBA, but regardless, you can create a function to do just that. Something like below.
Private Function SearchString(mysearch As String, mylist As Variant) As Long
Dim itm As Variant, idx As Long: idx = 0
If IsArray(mylist) Then
For Each itm In mylist
If mysearch = itm Then
SearchString = idx: Exit Function
End If
idx = idx + 1
Next
End If
SearchString = -1
End Function
And you can use it like this:
Private Sub CommandButton1_Click()
Dim i As Long
'do the search
i = SearchString("WhatImSearching", Me.ListBox1.List)
'select the item that match your search
If i <> -1 Then Me.ListBox1.Selected(i) = True
End Sub
I'm not saying that the function I created above is the most efficient way.
That is just an example to give you an idea for a workaround. HTH.
Important: This works in single column ListBox which have a 1D array list. If you need to work on multi-column ListBox, you'll have to tweak the function a little.

Sort Function (ascending) for Userform Listbox Excel

I am an IT enthusiast but I am not too good with programming or VBA. As a side project, I am compiling some data and would like to make it user friendly. I am new to forums so any advice would be welcome.
I have a Userform with a Listbox which has a large list of cities, but the list is unsorted. I understand i can go into the last page where I have the country capital list connected to the Listbox and sort the column there directly in the worksheet, but that would ruin my country list, so i would like to sort the list within the Userform Listbox, is there a way to do this?
I would also like to be able to add a Userform 'find' function within the Userform itself, as I have already done so, but I am unsure how to make it work despite trying some code, I failed, if you do know, then it would be great to hear whatever kind of advice, Thank you in advance.
Please find file in the link below with an image describing objectives and the code i currently have.
File:
https://www.sendspace.com/file/d4iaui
Sub Listb(target)
Location.ListBox1.List = Range("countrycapital").Value
For j = 0 To Location.ListBox1.ListCount - 1
Location.ListBox1.Selected(j) = False
Next j
currentrow = target.Row
'Location.Cells(19, 2) = Sheets("Practice List").Cells(target.Row, 3)
locval = target & ","
k = 0
For i = 1 To Len(locval)
Length = Abs(k - Application.WorksheetFunction.Search(",", locval, i))
Values = Mid(locval, i, Length - 1)
For j = 0 To Location.ListBox1.ListCount - 1
If Location.ListBox1.List(j) = Values Then
Location.ListBox1.Selected(j) = True
GoTo nxt
End If
Next j
nxt:
i = Application.WorksheetFunction.Search(",", locval, i)
k = i
Next i
Location.Show
End Sub
Sub newlocation()
Location.ListBox1.List = Range("countrycapital").Value
For j = 0 To Location.ListBox1.ListCount - 1
Location.ListBox1.Selected(j) = False
Next j
Location.Show
End Sub
Private Sub CommandButton1_Click()
Call ThisWorkbook.checkcriteria
End Sub
Private Sub CommandButton2_Click()
End Sub
Private Sub ListBox1_Click()
End Sub
Private Sub UserForm_Initialize()
Dim vaItems As Variant
Dim i As Long, j As Long
Dim vTemp As Variant
Me.ListBox1.AddItem "B" 'these new added values show on the userform
Me.ListBox1.AddItem "A" ' instead, I would like the original Listbox1...
Me.ListBox1.AddItem "D" ' ...incorporated within the sort function
Me.ListBox1.AddItem "C"
'Put the items in a variant array
vaItems = Me.ListBox1.List
'Steal code from John Walkenbach’s Excel Power Programming
'with VBA to sort the array
For i = LBound(vaItems, 1) To UBound(vaItems, 1) - 1
For j = i + 1 To UBound(vaItems, 1)
If vaItems(i, 0) > vaItems(j, 0) Then
vTemp = vaItems(i, 0)
vaItems(i, 0) = vaItems(j, 0)
vaItems(j, 0) = vTemp
End If
Next j
Next i
'Clear the listbox
Me.ListBox1.Clear
'Add the sorted array back to the listbox
For i = LBound(vaItems, 1) To UBound(vaItems, 1)
Me.ListBox1.AddItem vaItems(i, 0)
Next i
End Sub
Private Sub ListBox1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
HookListBoxScroll Location, Location.ListBox1
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
UnhookListBoxScroll
End Sub
My 2 cents :
- in order to sort things, I usually use the .Net Sort function. Some are accessible via Com Wrapper : CreateObject("System.Collections.ArrayList")
- this object has a .Contains function, that could be use by your Find function.
Hope this helps !

Scripting.Dictionary keys to Listbox VBA Excel

I have been working with VBA in excel and recently began working with the Scripting.Dictionary object. I hadn't run across any major problems until today.
Basically I am trying to populate a listbox with the Key values of a dictionary, then add one more value to the listbox. This results in the value not only being added to the listbox, but also to the dictionary as a key. I have attempted to copy the values from the dict.keys() array to a completely separate array, but still have the same issue. I assume this is a byref problem but have yet to figure out a solution. If anyone has any ideas that would be awesome.
Private Sub Setup_settingLst()
'Set Settings listbox items
'On Error GoTo ErrorExit
Dim list_ary() As Variant
Dim tmp As Variant
Dim i As Integer
settingLst.Clear
settingLst.Value = "-Select Setting-"
i = 0
tmp = tmp_dict.Keys()
If tmp_dict.Count > 1 Then
ReDim list_ary(0 To tmp_dict.Count)
For i = 0 To UBound(tmp)
list_ary(i) = tmp(i)
Next i
list_ary(tmp_dict.Count) = "Back"
Else
ReDim list_ary(0 To tmp_dict.Count - 1)
For i = 0 To UBound(tmp)
list_ary(i) = tmp(i)
Next i
End If
settingLst.List = list_ary
Erase list_ary
Exit Sub
ErrorExit:
End Sub
This seems to work
Private Sub UserForm_Click()
Dim dcValues As Scripting.Dictionary
Me.ListBox1.Clear
Set dcValues = FillDictionary
Me.ListBox1.List = dcValues.Keys
Me.ListBox1.AddItem "Back"
End Sub