![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Поиск в TStringList по первым символам его строк.
Кириешки © (2004-11-19 11:28:00)Есть TStringList содержащий 97 тыс. строк загружаемых из файла.
Мне надо чтобы можно было производить поиск в нем по ПЕРВЫМ символам его строк. Ну, чтобы было примерно так :
Допустим есть TStringList заполненый n-ным кол-вом строк, листбокс и едит. В едите пишется например "аб" и в листбокс поподают все строки из TStringList начинающиеся на "аб". Подскажите пожалуйста как это реализовать, и если можно с примерчиком.
Мастер (2004-11-19 12:26:00) [1]
TFilteredList=class(TStringList)
private
FFilteredList:TStrings;
FFilter: String;
isFiltered: Boolean;
procedure SetFiltered(const Value: Boolean);
function GetCountFiltered: Integer;
procedure ChangeFilter;
procedure SetFilter(const Value: String);
function GetFilteredItem(const index: Integer): String;
public
constructor Create;
destructor Destroy; override;
property Filter: String read FFilter write SetFilter;
property CountFiltered: Integer read GetCountFiltered;
property Filtered: Boolean read isFiltered write SetFiltered;
property FilteredItems[const index: Integer]: String read GetFilteredItem;
property FilteredList: TStrings read FFilteredList;
end;
procedure TFilteredList.ChangeFilter;
var
i: Integer;
Len: Integer;
begin
FFilteredList.Clear;
if Filter='' then isFiltered := False;
if not Filtered then Exit;
Len := Length(FFilter);
for i := 0 to Count-1 do
begin
if Copy(Self[i],1,Len)=FFilter then FFilteredList.Add(Self[i]);
end;
end;
constructor TFilteredList.Create;
begin
inherited Create;
FFilteredList := TStringList.Create;
end;
destructor TFilteredList.Destroy;
begin
FFilteredList.Free;
inherited;
end;
function TFilteredList.GetCountFiltered: Integer;
begin
Result := FFilteredList.Count;
end;
function TFilteredList.GetFilteredItem(const index: Integer): String;
begin
Result := FFilteredList[index];
end;
procedure TFilteredList.SetFilter(const Value: String);
begin
if FFilter=Value then Exit;
FFilter := Value;
ChangeFilter;
end;
procedure TFilteredList.SetFiltered(const Value: Boolean);
begin
isFiltered := Value;
ChangeFilter;
end;
begin...end (2004-11-19 12:22:00) [2]
> [7] Кириешки © (19.11.04 12:07)
> А что такое метод половинного деления?
Попробую объяснить. Только прошу всех не делать выводов о моей озабоченности. Я просто посмотрел на адрес e-mail товарища Кириешки.
Вот представь. Находишься ты в коридоре, в котором есть ряд из 11 дверей. За дверьми, в комнатах, сидят женщины - по одной в каждой комнате. Известно, что чем больше номер двери, тем больше возраст женщины, находящейся в соответствующей комнате.Тебе, например, нравятся только 20-летние.
Заходишь ты в среднюю (6-ю) дверь. А там сидит 10-летняя девочка. Понятно, что за дверьми с номерами меньше 6 находятся вообще младенцы (см. условие выше). А то, что нужно тебе, находится между 7-й и 11-й дверьми (включительно). Поэтому про двери номерами, меньшими 7, забываешь. Делишь оставшийся отрезок (от 7 до 11) пополам, получаешь 9. Заходишь, там сидит бабушка 70-ти лет. Тебе это не подходит, причём очевидно, что за двери с номерами больше 9 лучше не заглядывать. Оставшиеся двери, которые нужно просмотреть: 7..8. За одной из этих дверей твоя красавица и сидит.
ЮЮ (2004-11-19 12:13:00) [3]каждый раз область поиска сокращаешь в 2 раза, анализируя значение посередине.
Кириешки (2004-11-19 12:07:00) [4]Спасибо всем!
А что такое метод половинного деления? :((
***SPIDER*** (2004-11-19 11:55:00) [5]Примерно так:
...
StringList1.LoadFromFile(...);
...
procedure TForm1.Edit1Change(...);
var i,n:integer;
begin
ListBox1.Clear;
if StringList1.Count>0 then
for i:=0 to StringList1.Count-1 do
begin
if Copy(StringList1.Strings[i],1,Length(Edit1.Text))=Edit1.Text then
ListBox1.Items.Add(StringList1.Strings[i]);
end;
end;
...
Конечно методом половинного деления будет эффективнее, но лень писать.
ЮЮ (2004-11-19 11:52:00) [6]ну, например, так:
function FindFirst(List:TstringList; const Mask: String): integer;
var
cr, l, len, r, t: integer;
begin
if Mask = '' then begin
Result := -1;
Exit;
end;
len := length(Mask);
l := 0;
r := List.Count - 1;
t := (l + r) div 2;
while l <= r do begin
cr := AnsiCompareText(Copy(List[t], 1, len), Mask);
if cr = 0 then begin
result := t;
exit;
end else if cr < 0 then
l := t + 1
else
r := t - 1;
t := (l + r) div 2;
end;
result := -1;
end;
begin...end (2004-11-19 11:49:00) [7]
> [2] Кириешки © (19.11.04 11:41)
> А как искать - то я не понял?
Та же написано - методом половинного деления.
sniknik (2004-11-19 11:43:00) [8]len:= Length(Edit.Text);
for i:= 0 to StringList.Count-1 do
if copy(StringList.Strings[i], 1, len)='аб' then
листбокс.Add(StringList.Strings[i]);
но вообщето с 97 тыс строк уже можно думать о базах данных ;о)). или хотябы использовать базовые компоненты с их фильтрами, индексами, сортировкой, ...
Кириешки (2004-11-19 11:41:00) [9]ЮЮ
А как искать - то я не понял?
ЮЮ (2004-11-19 11:36:00) [10]TStringList должен быть отсортирован.
в едит.ончэйндж очищаешь листбокс, методом половинного деления очень быстро найдешь первую строку, совпадающую по маске и начиная с неё добавляешь в листбокс, пока строки удовлетворяют маске