Pomyślałem sobie, że skoro funkcja filter, o której pisałem, działa szybko, można spróbować odfiltrować z grubsza przy jej pomocy to, co na pewno nie pasuje do podanych kryteriów, a następnie przefiltrować resztę raz jeszcze, dokładniej.
lista_nazwisk2 to przefiltrowana wstępnie funkcją FILTER tablica z nazwiskami
For i = UBound(lista_nazwisk2) To 0 Step -1 ' dla każdego nazwiska w tablicy, zaczynając od ostatniej pozycji
' jeżeli nazwisko nie pasuje do wzorca
If Not UCase(lista_nazwisk2(i)) Like UCase(Me.TextBox2.Value) & "*" Then
' przesuwam wszystkie elementy lezace nizej o jedna pozycje do góry (zastępując niepasujący element)
For licznik = i To UBound(lista_nazwisk2) - 1
lista_nazwisk2(licznik) = lista_nazwisk2(licznik + 1)
Next licznik
' i usuwam ostatni element (zmieniam wymiar tablicy)
ReDim Preserve lista_nazwisk2(UBound(lista_nazwisk2) - 1)
End If
Next i
Na koniec sprawdziłem jeszcze tylko czy takie wstępne filtrowanie ma w ogóle sens. Przecież można po prostu przy pomocy pętli od razu przefiltrować wszystkie nazwiska.
Zmierzyłem czas wykonywania procedury z wstępnym filtrowaniem i bez niego. W przypadku listy 5600 nazwisk czas wylistowania z filtrowaniem wstępnym, po wpisaniu przypadkowej litery, wyniósł 0,05 sekundy. Bez wstępnego przefiltrowania – 0,22. Nieco bardziej konkretnie – dla litery „s” (511 nazwisk zaczynających się tą literą na mojej liście) czas wykonania wyniósł odpowiednio 0,38 i 1,23 sekundy. Prawie sekunda róznicy. Niby niewiele, ale w przypadku odświeżania ListBox’a jest to opóźnienie bardziej niż zauważalne. W przypadku róznych liter są to oczywiście różne wyniki (w zależności od tego jak wielka jest wstępnie odfiltrowana tablica) zawsze jednak jest to różnica na korzyść wstępnego przefiltrowania. Różnica ta oczywiście maleje w miarę wpisywania kolejnych liter i zawężania listy.
Na koniec, tytułem eksperymentu, zmierzyłem jeszcze czas wykonania innej procedury, która po prostu wstawia listę bezpośrednio do ListBox’a, a następnie usuwa z niego wszystkie elementy, które nie pasują do wzorca.
Private Sub TextBox1_Change()
Dim lista_nazwisk As Variant
Dim licznik As IntegerWith Worksheets("Nazwiska") ' nazwiska znajdują się w skoroszycie "Nazwiska"
' pobieram do tablicy listę nazwisk z arkusza.
lista_nazwisk = Range(Range("C4"), Range("C4").End(xlDown)).Value
End With
Me.ListBox1.List = lista_nazwisk ' wypelniam ListBox’a wartościami
For licznik = Me.ListBox1.ListCount - 1 To 0 Step -1
If Not UCase(Me.ListBox1.List(licznik)) Like UCase(Me.TextBox3.Value) & "*" Then
Me.ListBox1.RemoveItem licznik
End If
Next licznik
End Sub
W tym przypadku, dla wspomnianej już litery „s” czas odfiltrowania listy wyniósł 0,62 sekundy.
Przygotowując jednak projekt dla jednego z klientów chciałem przefiltrować listbox’a z kilkoma kolumnami. Wkrótce postaram się napisać o tym jaką metodę filtrowania wybrałem do projektu, dlaczego oraz jaki jest efekt.
Marcin

{ 3 comments… read them below or add one }
Jest już gdzieś to filtrowanie listboxa z kilkoma kolumnami?? Bardzo mnie interesuje jak to zrobiłeś
Rownież czekam niecierpliwie na wspomniane rozwiązanie
Tez sie nie moge doczekac tego rozwiazania. Mam nadzieje, ze wkrotce sie pojawi!