Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Вниз

Как работать с большим обьемом строк.   Найти похожие ветки 

 
DDS   (2004-02-04 10:49) [0]

Моя программа работает с большими обьемами строк.
Я использую TStringList, но таким макаром все работает медленно
и в него больше 64KB не запишешь. Как быстро манипулировать строками. Например WinAmpУ практически не составляет труда сортировать или просто загрузить плейлист на 2 тысячи файлов и осуществлять поиск по ним.


 
Beat   (2004-02-04 10:52) [1]

Почему больше 64Кб не загрузишь???

Тормозит??? List.Sorted - ?


 
Palladin   (2004-02-04 10:52) [2]


> в него больше 64KB не запишешь.

неправда


> все работает медленно

как определил?


 
Reindeer Moss Eater   (2004-02-04 10:53) [3]

Где написано про ограничение в 64К у TStringList?

Например WinAmpУ практически не составляет труда сортировать или просто загрузить плейлист на 2 тысячи файлов и осуществлять поиск по ним.

Где написано, что что он делает это? (грузит 2 тысячи имен)


 
Digitman   (2004-02-04 10:54) [4]


> в него больше 64KB не запишешь


что, прямо так и говорит, мол, отвали, не запишу больше 64KB ?


 
Beat   (2004-02-04 10:56) [5]

Удалено модератором


 
Reindeer Moss Eater   (2004-02-04 10:59) [6]

Удалено модератором


 
Beat   (2004-02-04 11:00) [7]

Reindeer Moss Eater:
сортируется то весь список, но ОДИН раз после его создания - иначе никак

з.ы. все ухожу _приятно_ было пообщаться...


 
Sergey_Masloff   (2004-02-04 11:04) [8]

В TStringList можно запихать несколько сотен Mb без проблем и тормозов, так теоретически пару гигов ;-)


 
Digitman   (2004-02-04 11:22) [9]

очевидно, следы чудес ведут к стринглисту в составе TMemo
тогда все вполне объяснимо


 
Плохиш   (2004-02-04 11:25) [10]


> Digitman © (04.02.04 11:22) [9]
> очевидно, следы чудес ведут к стринглисту в составе TMemo
> тогда все вполне объяснимо

под Вынь9x


 
DDS   (2004-02-04 16:49) [11]

Когда я в цикле перебираю все строки StringList то
это получается накладно по времени.

А насчет WinAmpА если кому-то надо могу скинуть скриншот
вот у меня MP3шек ровно 1849 это после того как я штук 500 нарезал.

А в WinAmpЕ вся эта груда строк сортируется причем и по тегам за несколько секунд. Я в словей проге только минут 5 жду пока прочту тег каждого файла. Да хотя бы грузить просто имена файлов в StringList идет долго.


 
Тимохов   (2004-02-04 16:51) [12]

2 млн строк в TStingList сортируется много меньше чем за 1 сек - поверь.
В своей проге ты ждешь 5 секунд не из за tstringlist, а из за неточностой в своем алгоритме.


 
Digitman   (2004-02-04 17:06) [13]


> DDS


перед заполнением списка :

- отключи автосортировку
- установи св-во Capacity равным макс.числу строк, которые планируется добавить (если это значение заранее известно тебе)

после заполнения списка перед вызовом методов поиска строк по их значению включи автосортировку


 
Reindeer Moss Eater   (2004-02-04 17:11) [14]

Удалено модератором


 
RealRascal   (2004-02-04 19:05) [15]

Не знаю мне кажется ничего лучше Tstringlist для работы с большим количеством строк не существует... И врядли удастся сократить время поиска написав свой алгоритм.
Ибо насколько я понимаю по (этот кусок из Classes)

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;

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 := AnsiCompareText(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;



если список несортированный, то поиск ведется простым перебором, а если сортированный - то бинарным поиском. А ничего эффективнее последнего для сортированных списков нет.


 
DDS   (2004-02-04 23:24) [16]

Удалено модератором


 
DDS   (2004-02-04 23:30) [17]

Sorted у меня отключен.
Я говорю про сортировку не встроенную.
Я согласен, что встроенная работает идеально быстро.
Я в проге сортирую списки по своим алгоритмам так как мне нужно сортировать например обр. порядке, вообщем не стандартным образом.

Я дкмаю, что алгоритмы сортировки гнилые, может кто-нибудь посоветовать инфу по сортировкам строк?

Да к стати у меня в циклах идет обращение к VCLкам я от этого избавился и вроде выиграл несколько секунд, но все же долго он с ними работает.

К примеру просто перебрать все строки списка и проверить каждую на вхождение подстроки. Если 1000 строк то ждать надо.


 
Юрий Зотов   (2004-02-04 23:57) [18]

> DDS (04.02.04 23:30) [17]

К примеру просто перебрать все строки списка и проверить каждую на вхождение подстроки. Если 1000 строк то ждать надо.


procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
T: DWORD;
begin
with TStringList.Create do
try
for i := 0 to 999999 do Add("asdladnadmasdmna");
T := GetTickCount;
for i := 0 to Count - 1 do Pos("AasasaS", Strings[i]);
Caption := IntToStr(GetTickCount - T)
finally
Free
end
end;

Результаты:
1. StringList без проблем вместил миллион строк.
2. Вызов Pos для каждой из миллиона строк - менее полсекунды.

Выводы напрашиваюся: "Дело было не в бобине..."


 
DDS   (2004-02-05 00:07) [19]

А из за частого обращения к визуальным компонентам в цикле могет отниматься много времени?


 
Юрий Зотов   (2004-02-05 00:28) [20]

> DDS (05.02.04 00:07) [19]

Если они при этом перерисовываются (например, обновляют отображаемые данные) - то перерисовка будет отнимать не просто много, а ОЧЕНЬ много времени.

Если в цикле есть инварианты - вытащите их наружу. Если есть обращения к свойствам объектов - закэшируйте их (например, простейшая замена свойства Text на обычную строку как-то сократила время работы одной программы с 4-х часов до 6 минут).

И т. д. Понимаете, при нормальном построении кода тех проблем, о которых Вы говорите, просто не может быть. Ну никак.


 
DDS   (2004-02-05 01:15) [21]

Короче понял я, похоже, в чем пробемма.
Есть у меня такая функция:

function TForm1.GetKey(str:string):integer;
var i:integer;
begin
result:=-1;
for i:=0 to List.Count-1 do
begin
if pos(str,List[i])>0
then begin result:=i; break; end;
end;
end;

Она очень часто используется в программе
и почти всегда примерно вот в таком виде:

for i:=0 to List.Count-1 do
begin
r:=GetKey(List[i]);
if r>0 then List_1.Add(List[i]); //к примеру
end;

И никак переделать нельзя.
Короче двойной цикл по всем элементам списка,
и так как списки не маленькие, то

2000 строк в одном и 2000 в другом
2000*2000=4 000 000

(все равно, что for i:=0 to 2000 do for j:=0 to 2000 do)
Если я правильно все написал, то как же мне быстро найти строку
в списке в которой содержится нужная подстрока.


 
dr Tr0jan   (2004-02-05 04:18) [22]

Народ, а не проще ли потоками (TStream) все сделать?


 
Palladin   (2004-02-05 07:18) [23]

хм... ну во первых советую использовать другой алгоритм Pos, не тот что в System, помоему библиотека называется FastStrings... во вторых искать не в TStringList, а слить в одну строку с указанием индексированых диапазонов для каждой строки, таким образом Pos можно будет вызвать лишь один раз для определения номера строки, в которой найден Str...


 
DHDD   (2004-02-05 07:37) [24]

>DDS (05.02.04 01:15) [21]
Ты понимаешь, что написал? 8-0


 
ЮЮ   (2004-02-05 07:59) [25]

>for i:=0 to List.Count-1 do
>begin
> r:=GetKey(List[i]);
> if r>0 then List_1.Add(List[i]); //к примеру
>end;

>И никак переделать нельзя.

r всегда > 0, т.к. List[k] как минимум равен List[k] для любого k
Поэтому весь цикл приводится к
List_1.Assign(List);


 
DDS   (2004-02-05 13:47) [26]

СПасибо, попробую, напишу ответ.


 
DDS   (2004-02-05 14:46) [27]

>ЮЮ
r не всегда > 0 потому, что функция GetKey возвращает -1 если ее параметр не является подстрокой другого списка. А если является то возвращает индекс строки. И функция тоже работает в цикле по всему списку.

>с указанием индексированых диапазонов для каждой строки

А по конкретней можно. Если я запишу весть StringList в одну строку и без проблем через POS то что надо, то как мне выразить номер строки зная номер найденный через POS.

>Palladin
А где FastStrings найти, на Мастерах или на Torry есть, у тебя есть ссылка?

Тоесть надо сделать GetKey без использования цикла.Вот идея, может и бредовая но это мне в голову пришло:
Берем StringList и записываем его как Text и записываем его в какой-нибудь
RichEdit. Дальше используя встроенный RichEdit1.FindText ищем текст и потом
выражаем номер строки в RichEdit из найденногою. Это и будет номер из StringList.
Я не говорю, что делать надо точно так, например можно не использовать визуальный
компонент RichEdit, а RichEdit1.FindText взять из ComCtrls.

Получаем:
RichEdit1.PlainText:=True;
RichEdit1.Text:=List.Text;
RichEdit1.SelStart:=RichEdit1.FindText(Str,1,Length(RichEdit1.Text),[]);
RichEdit1.SelLength:=0;


{{Из Delphi FAQ}}
Как получить номер строки memo, в которой находится курсор?
Для этого необходимо послать сообщение EM_LINEFROMCHAR.
LineNumber := Memo1.Perform(EM_LINEFROMCHAR, -1, 0);
{{Из Delphi FAQ}}

То же самое использовать для RichEdit.
Сильно не ругайтесь на все это.


 
Polevi   (2004-02-05 14:59) [28]

>DDS (05.02.04 14:46) [27]
а еще лучше установить MS SQL Server, он быстро ищет


 
Serginio666   (2004-02-05 15:14) [29]

DDS (05.02.04 01:15) [21]
Ищи половинным делением в сортированном TstringList или на неполное совпадение, или делай хэш таблицу например
http://rsdn.ru/Forum/Message.aspx?mid=419818&only=1


 
Palladin   (2004-02-05 15:17) [30]


> DDS (05.02.04 14:46) [27]

"индексированые диапазоны" может заумно конечно выразился, но на самом деле все просто...

s[1]:="abc";
s[2]:="def";
s[3]:="ghi";

строим массив индексов
indexArray:array [1..3] of integer;
заполняем его по следующему принципу
indexArray[1]:=1;
for i:=2 to 3 do indexArray[i]:=indexArray[i-1]+Length*s[i-1]+1;
добравшись до последнего индекса
SetLength(strCommon,indexArray[3]+Length(s[3]));
заполняем strCommon
for i:=1 to 3 do
begin
Move(s[i][1],strCommon[indexArray[i]],Length(s[i]));
strCommon[indexArray[i]-1]:=#13;
end;
дальше получаем позицию подстроки
nPos:=Pos(strSubStr,strCommon);
и бинарный поиск по indexArray (здесь писать не буду, сам пиши) тебе даст номер в исходном массиве строк...
faststrings ищи в инете


 
DDS   (2004-02-05 21:48) [31]

Я придумал кое-что: (FastString нашел)
Гружу список в STRING ищу подстроку а дальше перебираю символы от найденной позиции
1) влево пока не найду сивол начала строки 0Ah
2) вправо пока не найду сивол перевода строки 0Dh
Между ними моя строка. Фактически я выразил строку из списка. Получаю ее индекс через IndexOf.

List.Count ~ 2000 строк
Что придумал работает за ~40000мс
Но едрить-колотить старый вариант работает быстрее в 5 раз!!!!!!!!
Почему НОВЫЙ вариант медленнее там ведь операции простые и цикла нет.

{{{{ Старый вариант был: }}}}
procedure TForm1.GetKey(ind:integer);
var i:integer;
s:string;
begin
s:=Drugoi_List[ind]; //Подстрока
k:=-1;
for i:=0 to List.Count-1 do //Просто перебираю
begin
if pos(s,List[i])>0 //Нашел
then begin k:=i; break; end;
end;
end;

{{{{ Новый вариант: }}}}
procedure TForm1.GetKey(ind:integer);
var i,st_ln,ps:integer;
st,bx:string;
begin
tx:=List.Text; //Загружаю весь лист в STRING
tx_ln:=length(tx); //Ну и длину за одно
st:=Drugoi_List[ind]; //Подстрока
st_ln:=length(st); //И ее длина

{Ищу входждение подстроки st в строке всего списка tx}
ps:=FastPos(tx,st,tx_ln,st_ln, 1);
if ps>0 then
begin
ps:=FastPosBack(tx,ord(10),tx_ln,1, ps); //Ищу начало строки т.е. символ начала строки
bx:=copy(tx,ps,length(tx)-ps);
bx:=copy(bx,1,pos(ord(13),bx)+2); //С того самого начала по символ конца строки
k:=List.IndexOf(bx); //Ищу полученную строку в списке через IndexOf и получаю номер строки
end;
end;

{{{{ Использование: }}}}
for i:=0 to List.Count-1 do
GetKey(i,false);

Пробовал так же не каждый раз грузить весть лист в STRING а только 1ый.


 
DDS   (2004-02-06 00:10) [32]

ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!ВСЕ!
СПАСИБО ВАМ ЛЮДИ ДОБРЫЕ!
Я РЕШИЛ ЗАБИТЬ НА ВСЕ ЭТО И ОСТАВИТЬ ПРЕЖНИЙ ВАРИАНТ.
РАБОТАЕТ И ЛАДНО. ВСЕМ ЕЩЕ РАЗ СПАСИБО!


 
Anatoly Podgoretsky   (2004-02-06 09:05) [33]

Очень правильная позиция, в следующий рах когда например в программе будет постоянно выскакивать AV, также забей на ВСЕ


 
Serginio666   (2004-02-06 12:20) [34]

Я бы тебе посоветовал поиск по вхождению в строку метод Боуера-Мура Харрисона. Я его применяю например.
http://www.1c.hippo.ru/cgi-bin/predownl.cgi?id=2019

Очень быстрый поиск во всяком случае поиск в много мемегабайтных файлах укладываюся в секунду.


 
Serginio666   (2004-02-06 12:23) [35]

DDS (06.02.04 00:10) [32]
Прошу прощения за назойливость но позволю себе предложить Вам весьма неплохую статью
http://www.rsdn.ru/article/alg/textsearch.xml


 
DDS   (2004-02-08 01:37) [36]

Спасибо, но ссылка дохлая



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.009 c
14-53748
BOA_KAA
2004-01-28 11:27
2004.02.17
Proxy для WIndows


14-53707
pasha_golub
2004-01-29 14:20
2004.02.17
http://www.infoter.narod.ru/


1-53512
JediMaster
2004-02-05 17:02
2004.02.17
Поиск слова


14-53719
fool
2004-01-29 13:56
2004.02.17
восстановить удаленный файл, фаиловая система NTFS


1-53559
Silver_
2004-02-09 12:12
2004.02.17
Как проверить путь на его наличие





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский