Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Помогите отимизировать код небольшой функции


Автор: ДЫМ 28.6.2006, 22:37
Функция нужна для сортировки строк со смешанными данными (символы и числа).
http://forum.vingrad.ru/index.php?showtopic=101816

Код делает следующее: встречающиеся в строке числа добивает нулями слева, чтобы они были одной разрядности, например:

 fcGetFormattedString('Строка12Строка5', 5)
 возвращает строку:
 Строка00012Строка00005


Код

//**********************
// Функция форматирования строки
// 
function fcGetFormattedString(sStr: string; iDigits: Integer): string;
var i:Integer;
    sDigits:string;

begin
 sDigits:=''; Result:='';

 for i:=1 to Length(sStr)+1 do
 begin
  // выделяем из строки число
  if sStr[i] in ['0'..'9'] then
   begin
     sDigits:=sDigits+sStr[i];
   end
  else  // не цифры
   begin

    if sDigits<>'' then
     begin
      // добиваем текущее число нулями слева до iDigits
      Result:=Result+DupeString('0',iDigits-Length(sDigits))+sDigits;
      sDigits:='';
     end;
     if sStr[i]<>#0 then Result:=Result+sStr[i];
   end;// не цифры

 end;//for
end;

Вопрос вот в чем: можно ли как-то оптимизировать код, мне он представляется немного корявым и медленным.  

Автор: Palladin 28.6.2006, 23:34
Да нет, вроде всё нормально smile циклов я насчитал вообще только 1, хороший код, что тебе не устраивает, или прога тормозит smile  

Автор: Yanis 28.6.2006, 23:46
ДЫМ
Голова уже не варит. Завтра гляну.... Но код имхо не идеальный.


M
Girder
Не флуди...
 

Автор: Bose 29.6.2006, 14:50
разве что заменить
Код

 for i:=1 to Length(sStr)+1 do


на
Код

 var c:integer;
 
 c:=Length(sStr)+1;
 for i:=1 to c do


и вместо:
Код

Result:=Result+DupeString('0',iDigits-Length(sDigits))+sDigits;

писать
Код

Result:=Result+ StringOfChar('0',iDigits-Length(sDigits))+sDigits;


и ещё, как вариант, добавить
var ch:byte;
ch:=sStr[i];
и заменить все обращения к sStr[i] на обращения к ch

Время исполнения 1 000 000 итераций из 3х строк у меня было такое:
Original 1000 000 iter 0:00:19:547
My 100 0000 iter 0:00:19:422

Тестовые цикл был такой:
Код

  sl:=TstringList.Create;
  sl.Clear;
  sl.Add('xzv7ccv1basfd5ye4rghg;lnmvbnmuyit4dh5474hdhd');
  sl.Add('cxvfg576ghmbn87hjk,m874657hnfnvcb73324bvxc2d');
  sl.Add('xcbxc5478hb67367v367vc665784n476824c345vxc2d');
  MeasureTime;
  for i:=0 to 1000000 do
    t:= fcGetFormattedStringOrig(sl.Strings[i mod 3],(i mod 3)*2+4);
  sl.Free;
  Memo1.Lines.Add('Original 100 000 iter '+  MeasureTime);


процедура MeasureTime моя, она запоминает текущий GetTickCount и возвращает разницу между предыдушим запомненным значением и текущим. 

Автор: Alexeis 29.6.2006, 15:34
Быстрее я не смог придумать
Код

function fcGetFormattedString(sStr: Ansistring; iDigits: Integer): string;
var
   i, j, jn1, jn2 : Integer;
   n, l, l1, l2, ls, ld  : Integer;
   s : array of AnsiString;
   Fl : Boolean;

begin
 n := 0;
 Fl := False;
 for i := 1 to Length(sStr)
 do
   if not (sStr[i] in ['0'..'9'])
   then
     Fl := True
   else
     if Fl
     then
       begin
         Fl := False;
         Inc(n);
       end;

 l := 0;
 SetLength(s, n);
 j := 1;  
 for i := 0 to n - 1
 do
   begin
     jn1 := j;
     while (not (sStr[jn1] in ['0'..'9'])) and (jn1 <= Length(sStr))
     do
       Inc(jn1);

     jn2 := jn1;
     while (sStr[jn2] in ['0'..'9']) and (jn2 <= Length(sStr))
     do
       Inc(jn2);

     ld := iDigits - (jn2 - jn1);
     ls := jn2 - j;
     l1 := jn1 - j;
     l2 := jn2 - jn1;

     SetLength(s[i], ls + ld);
     Move(sStr[j], s[i][1], l1);
     FillChar(s[i][l1 + 1], ld, Ord('0'));
     Move(sStr[jn1], s[i][l1 + ld + 1], l2);

     Inc(l, ls + ld);
     j := jn2;
   end;

  j := 1;
  SetLength(Result, l);
  for i := 0 to n - 1
  do
    begin
      Move(s[i][1], Result[j], Length(s[i]));
      Inc(j, Length(s[i]));
    end;
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
  ShowMessage(fcGetFormattedString('Строка12Строка5стр117', 5));
end;


Добавлено @ 15:38 
Мининимальное количество операций выделения памяти
2 прохода по строке "делфийских" и 2 "ассемблерных" 

Автор: Bose 29.6.2006, 16:34
Код

Alexis 1000 000 iter 0:00:03:719
My 1000 000 iter 0:00:20:719


alexeis1, 
выигрыш в 17 секунд по сравнению с моим вариантом.  smile 
держи + за мастер-класс smile 

 

Автор: ДЫМ 1.7.2006, 00:03
Всем спасибо, alexeis1 особенно.  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)