Sortowanie tekstu zawierającego liczby

0

Mam problem z sortowaniem np. takich danych:

abc2
abc11
abc10
abc1
abc100

po sortowaniu porównując elementy funkcją AnsiCompareText wygląda to tak:

abc1
abc10
abc100
abc11
abc2

Jak najłatwiej zrobić, żeby poprawnie sortowało?

0

Ależ to jest poprawnie sortowane. Dla komputera liczba w stringu traktowana jest jak kolejna litera, która ma pozycję w alfabecie. Najprościej zastosować formatowanie typu abc001, abc010. Jak nie to trzeba napisać własna funkcję porównującą stringi.

0
Oleksy_Adam napisał(a)

Ależ to jest poprawnie sortowane. Dla komputera

A ja chcę żeby było sortowane po ludzku ;)

Oleksy_Adam napisał(a)

Najprościej zastosować formatowanie typu abc001, abc010.

Potrzebne mi to jest do sortowania listy plików, na których nazwy nie mam wpływu.

Oleksy_Adam napisał(a)

Jak nie to trzeba napisać własna funkcję porównującą stringi.

No właśnie zrobiłem funkcję dodającą zera przed liczbami podczas porównywania i działało, ale pytam czy jest jakiś bardziej optymalny i szybszy sposób?

0
function max(s:Tstrings):integer;
 var
 buf,i:integer;
 begin
 buf:=strtoint(s.Strings[0]);
 for i := 1 to s.Count-1 do
 if buf< strtoint(s.Strings[i])then buf:=strtoint(s.Strings[i]);
 result:=buf;
 end;
 function min(s:Tstrings):integer;
 var
 buf,i:integer;
 begin
 buf:=strtoint(s.Strings[0]);
 for i := 1 to s.Count-1 do
 if buf> strtoint(s.Strings[i])then buf:=strtoint(s.Strings[i]);
 result:=buf;
 end;
procedure us(a:integer) ;
 var
 i:integer ;
 begin
 for i:= 0 to Form1.ListBox1.Items.Count-1 do
 if strtoint(Form1.ListBox1.Items.Strings[i]) = a then
 begin
 Form1.ListBox1.Items.Delete(i);
 break;
 end;
 end;
Function nazwa(S:string):string;
 var
 i:integer;
 buf:string;
 begin
 buf:='';
 for i:=1 to length(s)do
 if not(upcase(s[i]) in ['A'..'Z']) then buf:=buf+s[i];
 result:=buf;
 end;
function ist(s:Tstrings;a:integer):boolean;
var
i:integer;
begin
for i:=0 to s.Count-1 do
if strtoint(s.Strings[i]) = a then result:=true;
end;
procedure sort(s:Tstrings);
var i,min1,max1:integer;
z:string;

begin
z:='';

for i:=1 to length(s.Strings[0])do
 if (upcase(s.Strings[0][i]) in ['A'..'Z']) then z:=z+s.Strings[0][i];

for i:=0 to Form1.listbox1.Items.Count-1 do
Form1.listbox1.Items.Strings[i]:=nazwa(Form1.listbox1.Items.Strings[i]);

min1:=min(s);
max1:=max(s);
i:=min1;

repeat
if ist(s,i) then
begin
Form1.ListBox2.Items.Append(z+inttostr(i));
us(i);
i:= min1;
end
else
inc(i);
until i> max1;

end;

Nie wiem dlaczego nie moge w zmiennej s korzystać z np. S.Append(costam) dlatego musiałem skorzystać z dodatkowego listbox2 gdzie jest wklejone wszystko posortowane;
może ktoś mądrzejszy to poprawi..
P.S. wiem ze nie jestem specem od optymalizacji kodu ale działa :D

0

zaznaczam ze on on później wkleja każdemu elementowi to co było w pierwszym przed liczbą...to jest juz łatwo skorygować za pomoą tablicy w której będzie zapisane wszystkie przedrostki

0

Niedawno miałem podobny problem. Dopisałem tylko własną metodę porównującą. Jako parametr podajemy listę do przesortowania i A-Z lub Z-A :-)

Oleksy_Adam: Rozwiązaniem nie jest układanie danych pod algorytm tylko algorytmu pod dane [!!!]

function CheckValues(s1,s2:string;asc:boolean): boolean;
  function isNumber(s:char):boolean;
  begin
    Result:=true;
    if s in ['0'..'9'] then
      Result:=true
    else
      Result:=false;
  end;
  function getNumber(s:string;st:byte;var i:byte):integer;
  var
    k:integer;
    res : string;
  begin
    res:='';
    k:=st;
    while(k<=length(s)) do
      if isNumber(s[k]) then begin
        res:=res+s[k];
        inc(k);
        i:=k;
      end else break;
    k:=StrToInt(res);
    Result:=k
  end;
var
  i,j      : byte;
  c1,c2    : single;
  st1,st2  : byte;
  len,len2 : byte;
  t1,t2    : string;
begin
  i:=1;   j:=1;
  st1:=1; st2:=1;
  t1:=''; t2:='';
  if Length(s1)>Length(s2) then begin
    len:=Length(s2);
    len2:=Length(s1);
  end else begin
    len:=Length(s1);
    len2:=Length(s2);
  end;
  while(i<=len) do begin
    if isNumber(s1[i]) and isNumber(s2[i]) then begin
      c1:=getNumber(s1,st1,st1);
      c2:=getNumber(s2,st2,st2);
      if st1>st2 then i:=st1 else i:=st2;
      if c1>c2 then begin
        t1:=t1+'2';
        t2:=t2+'1';
      end else begin
        if c1<>c2 then begin
         t1:=t1+'1';
         t2:=t2+'2';
        end else begin
         t1:=t1+'1';
         t2:=t2+'1';
        end;
      end
    end else begin
      if s1[i]>s2[i] then begin
        t1:=t1+'2';
        t2:=t2+'1';
      end else begin
        if s1[i]<>s2[i] then begin
          t1:=t1+'1';
          t2:=t2+'2';
        end else begin
          t1:=t1+'1';
          t2:=t2+'1';
        end;
      end;
      inc(i);
      inc(st1);
      inc(st2);
    end;
  end;
  j:=i;
  for i:=j to len2 do begin
    if Length(s1)>Length(s2) then begin
      t1:=t1+'2';
      t2:=t2+'1';
    end else begin
      t1:=t1+'1';
      t2:=t2+'2';
    end;
  end;
  c1:=StrToFloat(t1);
  c2:=StrToFloat(t2);
  if asc then
    if c1>c2 then Result:=true else Result:=false
  else
    if c1<c2 then Result:=false else Result:=true;
end;

procedure SortList(var List:TStringList;asc:boolean);
var
  InPo,
  InSz : integer;
  tmp  : string;
begin
  if asc then
    for InPo := 0 to List.Count-1 do begin
      tmp:=List[InPo];
      for InSz := InPo-1 DownTo 0 do begin
          if CheckValues(tmp,List[InSz],true) then
          List[InSz+1]:=List[InSz]
        else
          Break;
      end;
      List[InSz+1]:=tmp;
    end
  else
    for InPo := 1 to List.Count-1 do begin
      tmp:=List[InPo];
      for InSz := InPo-1 DownTo 0 do begin
          if not CheckValues(tmp,List[InSz],false) then
          List[InSz+1]:=List[InSz]
        else
          Break;
      end;
      List[InSz+1]:=tmp;
    end
end;

</delphi>

1 użytkowników online, w tym zalogowanych: 0, gości: 1