Entwickler-Ecke

Sonstiges (Delphi) - Zahlen im Stringgrid nach mehreren Spalten sortieren


mauri260493 - Fr 29.10.10 18:02
Titel: Zahlen im Stringgrid nach mehreren Spalten sortieren
Hi Leute,

ich möchte eine Fußball Tabelle in meinem Programme erstellen.
Die soll folgendermaßen aussehen:

Screenshot
( Platzierungen sollen erst nach dem sortieren eingefügt werden)

Die Daten speicher ich in einem Array und schreibe sie dann ins StringGrid.

Nun müssen die aber noch sortiert werden.

Nach einer Spalte zu sortieren macht überhaupt kein Problem, aber da bei Punktegleichheit die Tordifferenz bzw. geschossene Tore und kassierte Tore einbezogen werden müssen, gibts da ein Problem. -.-

Habe folgenden Code gefunden:
http://swissdelphicenter.ch/de/showcode.php?id=449

Der funktioniert jedoch nicht. Ich schätze, dass es daran liegt, dass er versucht die Strings zu vergleichen, und nicht die Zahlen.

Wie ich den umschreiben soll, weiß ich aber nicht.

Kann jemand von euch mir helfen?

Danke schonmal. :)

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen.


Bergmann89 - Fr 29.10.10 19:44

Hey,

eigentlich ist es egal, ob den String oder die eigentliche Zahl zum Vergleichen nimmt, weil '0' auch als String kleiner ist als '2'.
Was genau geht denn nicht bei dem Code, den du gefunden hast?
Wie hast du das ganze bei dir eingebunden?

MfG Bergmann.


bummi - Fr 29.10.10 21:12

kleine Einstriegshilfe, bitte selbst anpassen

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
unit StringridSort;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls;

type
  TMy2Compare=Function(Const R1c1,R2c1,R1c2,R2c2:String):Boolean;

  TStringGridX = class(TCustomGrid)
  public
  procedure MoveRow(FromIndex, ToIndex: Longint);
  procedure MoveColumn(FromIndex, ToIndex: Longint);
  procedure DeleteRow(ARow: Longint);
  procedure DeleteColumn(ACol: Longint);
  end;

  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TStringGridX }

procedure TStringGridX.DeleteColumn(ACol: Integer);
begin
inherited;
end;

procedure TStringGridX.DeleteRow(ARow: Integer);
begin
inherited;
end;

procedure TStringGridX.MoveColumn(FromIndex, ToIndex: Integer);
begin
inherited;
end;

procedure TStringGridX.MoveRow(FromIndex, ToIndex: Integer);
begin
inherited;
end;



Function Compare2RowsIamSureTheyAreNumericDesc(Const R1c1,R2c1,R1c2,R2c2:String):Boolean;
begin
  if StrToInt(R1c1)=StrToInt(R2c1) then Result := StrToInt(R1c2)<StrToInt(R2c2)

  else Result:=StrToInt(R1c1)<StrToInt(R2c1);
end;


Function Compare2RowsIamSureTheyAreNumericAsc(Const R1c1,R2c1,R1c2,R2c2:String):Boolean;
begin
  if StrToInt(R1c1)=StrToInt(R2c1) then Result := StrToInt(R1c2)>StrToInt(R2c2)

  else Result:=StrToInt(R1c1)>StrToInt(R2c1);
end;


procedure QuickSortSG2Rows(a:TStringGrid;Column1,Column2:Integer; lo, hi: integer;Compare:TMy2Compare);
var i, j, h: integer;
    s1,s2:String;
begin
  // lo ist der unterste Index, hi ist der oberste Index des
  // zu sortierenden (Teil-)Feldes a
  i:=lo;
  j:=hi;
  s1:=a.Cells[Column1,(lo+hi) div 2];
  s2:=a.Cells[Column2,(lo+hi) div 2];
  //Aufteilung
  while i<=j do
      begin
        While (i<=j) and Compare(s1,a.Cells[Column1,i],s2,a.Cells[Column2,i]) do inc(i);
        While (i<=j) and Compare(a.Cells[Column1,j],s1,a.Cells[Column2,j],s2) do dec(j);
        if (i<=j) then
        begin
          TStringGridX(a).MoveRow (i,j);
          if j-i>1 then TStringGridX(a).MoveRow (j-1,i);
          inc(i); dec(j);
        end;
      end;

  // Rekursion
  if lo<j then QuickSortSG2Rows(a, Column1,Column2, lo, j, Compare);
  if i<hi then QuickSortSG2Rows(a, Column1,Column2, i, hi, Compare);
end;



procedure TForm1.Button1Click(Sender: TObject);
begin
  QuickSortSG2Rows(StringGrid1,1,21, StringGrid1.RowCount - 1 ,Compare2RowsIamSureTheyAreNumericAsc)
end;

end.


jaenicke - Sa 30.10.10 07:48

Am besten mach es dir ganz einfach und benutze eine TListView. Da brauchst du nur OnCompare zu implementieren, das Sortieren geht komplett automatisch (einfach Sort aufrufen).

Außerdem siehts tausendmal besser aus.


toms - Sa 30.10.10 08:40

Ersetze AnsiCompareStr durch eine eigene Funktion:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
type
  TMoveSG = class(TCustomGrid);

// Zahlen vergleichen
function CompareInt(i1, i2: Integer): Integer;
// Result: -1 if i1 < i2, 1 if i1 > i2, 0 if i1 = i2
begin
  if i1 < i2 then
    Result := -1
  else if i1 > i2 then
    Result := 1
  else
    Result := 0;
end;

// Strings vergleichen
function CompareValues(const S1, S2 : String): Integer;
var
  V1, V2 : Integer;
  C1, C2 : Integer;
begin
  Val(S1, V1, C1);
  Val(S2, V2, C2);
  if (C1 = 0and (C2 = 0then  // Wenn beides Zahlen
     Result := CompareInt(V1, V2)
  else  // sonst wenn String/String od. String/Zahl
     Result := AnsiCompareStr(S1, S2);
end;

procedure SortGridByCols(Grid: TStringGrid; ColOrder: array of Integer; Fixed: Boolean);
var
  I, J, FirstRow: Integer;
  Sorted: Boolean;

  function Sort(Row1, Row2: Integer): Integer;
  var
    C: Integer;
  begin
    C := 0;
    Result := CompareValues(Grid.Cols[ColOrder[C]][Row1], Grid.Cols[ColOrder[C]][Row2]);
    if Result = 0 then
    begin
      Inc(C);
      while (C <= High(ColOrder)) and (Result = 0do
      begin
        Result := CompareValues(Grid.Cols[ColOrder[C]][Row1], Grid.Cols[ColOrder[C]][Row2]);
        Inc(C);
      end;
    end;
  end;

begin
  for I := 0 to High(ColOrder) do
    if (ColOrder[I] < 0or (ColOrder[I] >= Grid.ColCount) then
      Exit;

  if Fixed then
    FirstRow := 0
  else
    FirstRow := Grid.FixedRows;

  J := FirstRow;
  Sorted := True;
  repeat
    Inc(J);
    for I := FirstRow to Grid.RowCount - 2 do
      if Sort(I, I + 1) > 0 then
      begin
        TMoveSG(Grid).MoveRow(i + 1, i);
        Sorted := False;
      end;
  until Sorted or (J >= Grid.RowCount + 1000);
  Grid.Repaint;
end;


mauri260493 - Sa 30.10.10 12:29

Erstmal Danke für eure Mühen :)

Toms Idee funktioniert auch soweit.

Ein Problem hab ich jedoch noch.

Alle Spalten werden aufwärts sortiert.
Eigentlich müsste ich die Punkte abwärts, dann die Tordifferenz abwärts, dann die Tore abwärts und dann die Gegentore aufwärts sortieren.

Kann man das so anpassen?


bummi - Sa 30.10.10 12:47

wenn Du statt ColOrder: array of Integer
ein Array übergibst vom Typ
TMySortInfo=record
Col:Integer;
asc:Boolean;
end;

kannst Du entweder verschiende Compareroutinen intern aufrufen oder der Compareroutine die Asc -Info durchreichen und intern gegf. mit vertauschten Vorzeichen arbeiten.


mauri260493 - Sa 30.10.10 13:45

Klingt gut, aber ich weiß nicht wie ich die Routine ändern muss/kann :(


toms - Sa 30.10.10 14:17


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
type
  TMoveSG = class(TCustomGrid);

type
  TSortInfo = record
    Col: Integer;
    asc: Boolean;
  end;

// Zahlen vergleichen

function CompareInt(i1, i2: Integer): Integer;
// Result: -1 if i1 < i2, 1 if i1 > i2, 0 if i1 = i2
begin
  if i1 < i2 then
    Result := -1
  else if i1 > i2 then
    Result := 1
  else
    Result := 0;
end;

// Werte vergleichen

function CompareValues(const S1, S2: string; Reverse: Boolean): Integer;
var
  V1, V2: Integer;
  C1, C2: Integer;
begin
  Val(S1, V1, C1);
  Val(S2, V2, C2);
  if (C1 = 0and (C2 = 0then // Wenn beides Zahlen
    Result := CompareInt(V1, V2)
  else // sonst wenn String/String od. String/Zahl
    Result := AnsiCompareStr(S1, S2);
  if not Reverse then
    Result := 0 - Result;
end;

procedure SortGridByCols(Grid: TStringGrid; SortInfo: array of TSortInfo;
  Fixed:
  Boolean);
var
  I, J, FirstRow: Integer;
  Sorted: Boolean;

  function Sort(Row1, Row2: Integer): Integer;
  var
    C: Integer;
  begin
    C := 0;
    Result := CompareValues(Grid.Cols[SortInfo[C].Col][Row1],
      Grid.Cols[SortInfo[C].Col][Row2], SortInfo[C].asc);
    if Result = 0 then
    begin
      Inc(C);
      while (C <= High(SortInfo)) and (Result = 0do
      begin
        Result := CompareValues(Grid.Cols[SortInfo[C].Col][Row1],
          Grid.Cols[SortInfo[C].Col][Row2], SortInfo[C].asc);
        Inc(C);
      end;
    end;
  end;

begin
  for I := 0 to High(SortInfo) do
    if (SortInfo[I].Col < 0or (SortInfo[I].Col >= Grid.ColCount) then
      Exit;

  if Fixed then
    FirstRow := 0
  else
    FirstRow := Grid.FixedRows;

  J := FirstRow;
  Sorted := True;
  repeat
    Inc(J);
    for I := FirstRow to Grid.RowCount - 2 do
      if Sort(I, I + 1) > 0 then
      begin
        TMoveSG(Grid).MoveRow(i + 1, i);
        Sorted := False;
      end;
  until Sorted or (J >= Grid.RowCount + 1000);
  Grid.Repaint;
end;



procedure TForm1.Button1Click(Sender: TObject);
const
  MySortInfo: array[0..3of TSortInfo =
    ((col: 1; asc: True),
    (col: 2; asc: True),
    (col: 3; asc: True),
    (col: 4; asc: False)
    );
begin
  SortGridByCols(StringGrid1, MySortInfo, true);
end;


bummi - Sa 30.10.10 14:24

ich lehne mich mal an toms Code an


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
type
  TMoveSG = class(TCustomGrid);
  TSortInfo=Record
    col:Integer;
    asc:Boolean;
  End;

// Zahlen vergleichen
function CompareInt(i1, i2: Integer): Integer;
// Result: -1 if i1 < i2, 1 if i1 > i2, 0 if i1 = i2
begin
  if i1 < i2 then
    Result := -1
  else if i1 > i2 then
    Result := 1
  else
    Result := 0;
end;

// Strings vergleichen
function CompareValues(const S1, S2 : String;asc:Boolean): Integer;
var
  V1, V2 : Integer;
  C1, C2 : Integer;
begin
  Val(S1, V1, C1);
  Val(S2, V2, C2);
  if (C1 = 0and (C2 = 0then  // Wenn beides Zahlen
     Result := CompareInt(V1, V2)
  else  // sonst wenn String/String od. String/Zahl
     Result := AnsiCompareStr(S1, S2);
  if not Asc then Result := Result * -1;

end;

procedure SortGridByCols(Grid: TStringGrid; ColOrder: array of TSortInfo; Fixed: Boolean);
var
  I, J, FirstRow: Integer;
  Sorted: Boolean;

  function Sort(Row1, Row2: Integer): Integer;
  var
    C: Integer;
  begin
    C := 0;
    Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc);
    if Result = 0 then
    begin
      Inc(C);
      while (C <= High(ColOrder)) and (Result = 0do
      begin
        Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc);
        Inc(C);
      end;
    end;
  end;

begin
  for I := 0 to High(ColOrder) do
    if (ColOrder[I].col < 0or (ColOrder[I].col >= Grid.ColCount) then
      Exit;

  if Fixed then
    FirstRow := 0
  else
    FirstRow := Grid.FixedRows;

  J := FirstRow;
  Sorted := True;
  repeat
    Inc(J);
    for I := FirstRow to Grid.RowCount - 2 do
      if Sort(I, I + 1) > 0 then
      begin
        TMoveSG(Grid).MoveRow(i + 1, i);
        Sorted := False;
      end;
  until Sorted or (J >= Grid.RowCount + 1000);
  Grid.Repaint;
end;
procedure TForm1.Button1Click(Sender: TObject);
const
  MyArray: array[0..3of TSortInfo =
    ((col: 1; asc: true),
     (col: 2; asc: true),
     (col: 3; asc: true),
     (col: 4; asc: false)
     );
begin
  SortGridByCols(StringGrid1,MyArray,true);
end;

end.


mauri260493 - Sa 30.10.10 17:19

Bummi, du bist meine Rettung.

Funktioniert einwandfrei :)

Vielen vielen Dank an euch alle ;)