views:

224

answers:

2

I want to clean a list box by checking it against two other list boxes.

  • Listbox1 would have the big list of items
  • Listbox2 would have words I want removed from listbox1
  • Listbox3 would have mandatory words that have to exist for it to remain in listbox1

Below is the code I've got so far for this, it's VERY slow with large lists.

// not very efficient 
Function checknegative ( instring : String; ListBox : TListBox ) : Boolean;
Var
  i : Integer;
Begin
  For I := listbox.Items.Count - 1 Downto 0 Do
  Begin
    If ExistWordInString ( instring, listbox.Items.Strings [i], 
      [soWholeWord, soDown] ) = True 
    Then
    Begin
      result := True;  //True if in list, False if not.
      break; 
    End
    Else
    Begin
      result := False;
    End;
  End;
  result:=false;
End;

Function ExistWordInString ( aString, aSearchString : String;
  aSearchOptions : TStringSearchOptions ) : Boolean;
Var
  Size : Integer;
Begin
  Size := Length ( aString );
  If SearchBuf ( Pchar ( aString ), Size, 0, 0, aSearchString, aSearchOptions ) <> Nil Then
  Begin
    result := True;
  End
  Else
  Begin
    result := False;
  End;
End;
+2  A: 

If this is working on a listbox, it's probably taking a lot of time to repaint everything every time. You can disable this behavior. Surround the outermost loop with this:

listbox.Items.BeginUpdate;
try
  //do the loop here
finally
  listbox.Items.EndUpdate;
end;

Also, you can assign a boolean directly to the evaluation of a boolean expression, which will save some time on your inner loop. So:

Function ExistWordInString ( aString, aSearchString : String; aSearchOptions : TStringSearchOptions ) : Boolean;
Var
  Size : Integer;
Begin
  Size := Length ( aString );
  result := SearchBuf ( Pchar ( aString ), Size, 0, 0, aSearchString, aSearchOptions ) <> Nil;
End;

Not sure how much of a difference that will make, though. If you make these changes and it's still too slow, try running your program through a profiler such as Sampling Profiler, which will help you see what your code is spending most of its time doing.

Mason Wheeler
I'm doing the begin/endupdate and I'll defiantly be looking at the sampling profiler.
Brad
Looking at your StringListComp, it might give me some better ways around what I'm doing...
Brad
@Brad: You mean the library on my blog? That's really only useful for comparing entire strings. But when you can use it, it's very useful.
Mason Wheeler
yes, the lib on your blog, Just wish it was able to compare words vs just strings.. :P
Brad
+3  A: 

If you do anything that loops with a TStrings instance in a control it may be beneficial to create a temporary TStringList instance, assign the control items to it, then use the temporary list.

The reason for that is that the Items property in a list box, combo box or similar is implemented via a proxy class that doesn't hold the strings itself, but which uses Windows messages like LB_GETCOUNT and LB_GETTEXT to retrieve the elements directly from the native Windows control. If you access a string list item several times then the overhead of the repeated message handling will add up.

mghie
Great information to know!
Brad