Delphi: TStringList's Find, IndexOf and Sort

The key: Find Sort prior to ordering, Indexof without sorting.

 

Internal TStringList find relevant data. Debugging code to be known when the pain, after wasting countless hours, only a step by step tracking, only made

Now Find method returns the Index always wrong, while depressed at that time to hand press the F1 key, the Help document Find unfolding before our eyes, for the

Such functions are described:
Locates The index for the sorted A String in List A and indicates that with Whether A String

value already exists in the list.


Note also stressed again in part:

Only use Find with sorted lists. For unsorted lists, use the IndexOf method instead.

 

Blame themselves sometimes lazy, without the knowledge of the jilted accustomed IndexOf, easy to use the new functions. But I also became interested in why Find data can only return to normal after using it TStringList.Sort method?

 

The old way, jump directly Classes file to view the source code:

function TStringList.Find(const S: string; var Index: Integer): Boolean;
var
L, H, I, C: Integer;
begin
Result := False;
L := 0;
H := FCount - 1;
while L <= H do
begin
    I := (L + H) shr 1;
    C := CompareStrings(FList^[I].FString, S);
    if C < 0 then L := I + 1
    else begin
      H := I - 1;
      if C = 0 then
      begin
        Result := True;
        if Duplicates <> dupAccept then L := I;
      end;
    end;
end;
Index := L;
end;

Or be shocked, how feel so complicated, look carefully understand, the original is a binary search algorithm. Ha ha.
L, H and the variable representing Low High, (L + H) shr 1 is to compute intermediate values, exactly equal to the (L + H) div 2, for binary,

Right one equivalent divisible by 2. Wherein CompareStrings is used to compare the size of the two strings:

function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
if CaseSensitive then
    Result := AnsiCompareStr(S1, S2)
else
    Result := AnsiCompareText(S1, S2);
end;

CaseSensitive here used to mark whether case-sensitive, AnsiCompareStr is case-sensitive, AnsiCompareText the

on the contrary. Also in the Help documentation specially described determination when the two functions, is smaller than the lowercase characters uppercase characters, such as 'a' < 'A'

. Please note that this is not the same place with the ASCII (if chasing it forever, you can find these two functions is a package to the API,

And it encapsulates the two versions of Linux and Windows).

 

At this time, we return to the Find function itself, will find that only C <0 and C = 0, which means it can only be determined search condition in ascending

Arranged StringList.

 

Can not help, then looked Sort method.

procedure TStringList.Sort;
begin
CustomSort(StringListCompareStrings);
end;

 

Simply can not be simple, one line statement. CustomSort is a common way for users to customize the comparison rules to sort.

StringListCompareStrings parameter is placed in a custom comparison function rules:

TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

CustomSort code is as follows:

procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
if not Sorted and (FCount > 1) then
begin
    Changing;
    QuickSort(0, FCount - 1, Compare);
    Changed;
end;
end;

 

Changing and Changed mainly used to trigger FOnChanging and FOnChanged, the specific content can look at the code yourself. and

QuickSort is using a fast sort algorithm comparison rules and user-defined sort, and talking into QuickSort code:
Procedure TStringList.QuickSort (L, R & lt: Integer; SCompare: TStringListSortCompare);
var
the I, J, P: Integer ;
the begin
REPEAT
    the I: = L;
    J: = R & lt;
    P: = (L + R & lt) SHR. 1;
    REPEAT
      the while SCompare (Self, the I, P) <0 do Inc is an (the I);
      the while SCompare (Self, J, P )> 0 do On Dec (J);
      IF the I <= J the then
      the begin
        ExchangeItems (the I, J);
        IF P = the I the then
          P: = J
        the else IF P = J the then
          P: = the I;
        Inc is an (the I);
        On Dec ( J);
      End;
    an until the I> J;
    if L < J then QuickSort(L, J, SCompare);
    L := I;
until I >= R;
end;

Haha, it is this period

while SCompare(Self, I, P) < 0 do Inc(I);
while SCompare(Self, J, P) > 0 do Dec(J);

It is in ascending order such that TStringList. So far, roughly figured out the reason.

IndexOf look at how to achieve the search, the beginning I think it is certainly using a For loop through each Item, encountered the same content

Then out of the loop, and found that it really is to do so, but the middle of doing some optimization, if StringList has been sorted, it

Will automatically use the more efficient the Find method to find, in addition to its use as a Result loop variable, use of resources is overwhelming.

code show as below:

function TStringList.IndexOf(const S: string): Integer;
begin
if not Sorted then Result := inherited IndexOf(S) else
    if not Find(S, Result) then Result := -1;
end;

Wherein inherited IndexOf method used in the parent class TStrings

function TStrings.IndexOf(const S: string): Integer;
begin
for Result := 0 to GetCount - 1 do
    if CompareStrings(Get(Result), S) = 0 then Exit;
Result := -1;
end;

Get the code in the method of the TStrings is a pure virtual function.

function Get(Index: Integer): string; virtual; abstract;

Pure virtual function how can pour. Since it can be, there is only one possibility is that the child TStringList class is implemented in Get method. back to

TStringList, when she saw the following code:

function TStringList.Get(Index: Integer): string;
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Result := FList^[Index].FString;
end;

He used to get the string specified row. Analysis came to an end.
 

》》》》》》》》》》》》》》》》》》》》》》》》》》》》

 

Find a binary search, the speed should be the fastest, while indexof default for all item of reincarnation. But before the application must first find sort sort or else return index error.

 

Examples are as follows:

 

var  lst:TStringList ;
     i:Integer ;
begin

  lst:=TStringList.Create ;

  try

    lst:=TStringList.Create ;
    lst.CaseSensitive :=true;
    lst.Delimiter :="","";
    lst.DelimitedText :=Edit1.Text ;

    ShowMessage(IntToStr(lst.IndexOf(Edit2.Text) ));
    lst.Sort ;
        if lst.Find(Edit2.Text ,i) then
      ShowMessage(IntToStr(i));
  finally

    lst.Free ;
  end;


eidt2 follows string 010a, 010A, 200a, 200b, 905a

Guess you like

Origin www.cnblogs.com/jijm123/p/11482138.html