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?
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?
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.
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?
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
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
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>