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