View Full Version : Solved: Partial String ListBox search to populate another ListBox
tccmdr
06-16-2008, 08:26 PM
Hello Gurus :bow: 
 
I have a UserForm ListBox which is poulated from a range in a worksheet.
I have a TextBox above the ListBox in which I enter text. As I enter in each character in the string the first item in the ListBox to match the string is highlighted - like scrolling through the contents.
 
I have another ListBox in which I want to populate with all items from the first ListBox that match the string, not just the first:think: 
 
So both events will be occuring at the same time, dynamically, as I enter each string character.
 
Am I missing something simple......all help appreciated: pray2:
mikerickson
06-16-2008, 11:35 PM
This assumes that the list in ListBox1 is sorted. 
I infer that there are a lot of entries in ListBox1. 
Private Sub TextBox1_Change()
    Dim dataRRay As Variant
    Dim matchingArray As Variant
    
    dataRRay = ArrayFromListBoxOne()
    
    With Me
        matchingArray = ArrayOfPartialMatches(dataRRay, .TextBox1.Text)
        .ListBox2.List = matchingArray
        On Error Resume Next
        .ListBox1.ListIndex = Application.Match(.TextBox1.Text & "*", dataRRay, 0) - 1
        On Error GoTo 0
    End With
End Sub
Function ArrayFromListBoxOne() As Variant
    Dim outRRay As Variant, i As Long
    With Me.ListBox1
        ReDim outRRay(0 To .ListCount - 1)
        For i = 0 To .ListCount - 1
            outRRay(i) = .List(i)
        Next i
    End With
    ArrayFromListBoxOne = outRRay
End Function
Function ArrayOfPartialMatches(ArrayOfStrings As Variant, ByVal startingString As String) As Variant
    Dim outRRay As Variant
    Dim minIndex As Long, maxIndex As Long
    Dim matchStr As String, i As Long
    Dim low As Long, mid As Long, high As Long
    
    startingString = LCase(startingString)
    
    Rem restrict search
    matchStr = Left(startingString, 1) & Chr(255)
    low = LBound(ArrayOfStrings)
    high = UBound(ArrayOfStrings)
    Do
        mid = (low + high) / 2
        
        If LCase(ArrayOfStrings(mid)) < matchStr Then
            low = mid
        Else
            high = mid
        End If
    Loop Until high = low + 1
    maxIndex = low
    
    matchStr = Chr(Asc(startingString & vbCr) - 1) & Chr(255)
    low = LBound(ArrayOfStrings)
    high = UBound(ArrayOfStrings)
    Do
        mid = (low + high) / 2
        
        If LCase(ArrayOfStrings(mid)) < matchStr Then
            low = mid
        Else
            high = mid
        End If
    Loop Until high = low + 1
    minIndex = high + (low = LBound(ArrayOfStrings))
    
    Rem begin search
    high = maxIndex - minIndex + 1
    mid = 0
    If 0 < high Then
        ReDim outRRay(1 To high)
        For i = minIndex To maxIndex
            If LCase(ArrayOfStrings(i)) Like startingString & "*" Then
                mid = mid + 1
                outRRay(mid) = ArrayOfStrings(i)
            End If
        Next i
    End If
    
    If mid = 0 Then
        ReDim outRRay(0 To 0): outRRay(0) = vbNullString
    Else
        ReDim Preserve outRRay(1 To mid)
    End If
    
    ArrayOfPartialMatches = outRRay
End Function
tccmdr
06-16-2008, 11:46 PM
Thanks Mike :clap: ......but please don't tell me you just through this together
mikerickson
06-17-2008, 06:25 PM
You're welcome.
Once I saw that a sorted list could have the search restricted by a binary search (i.e. neither the restriction nor the search would take forever), the rest was just flowed.
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.