Einzelnen Beitrag anzeigen

nahpets
(Gast)

n/a Beiträge
 
#3

Re: Sortierung von Stringlisten ab unbestimmter Position

  Alt 10. Okt 2008, 16:34
Hallo alzaimar,
Zitat von alzaimar:
1. Ermittle die Delimiter-Positionen (GetStartPos und GetNextPos) je Zeile einmal im Vorfeld und speichere die Ergebnisse zwischen. Dadurch werden redundante Mehrfachaufrufe vermieden.

2. Die Funktionen GetStartPos und GetNextPos sollten private Methoden deiner Klasse werden

3. Deine Sorge bezüglich des 'MyCompare'-Funktion ist unbegründet. Keiner wird je diese Funktion zu Gesicht bekommen, sie ist doch lokal in der Unit und damit unsichtbar. Entferne die Prüfung 'If item is...', denn das brauchst Du doch nicht und es frisst Performance.
da komm' ich jetzt nicht so ganz mit:
Zitat:
2. Die Funktionen GetStartPos und GetNextPos sollten private Methoden deiner Klasse werden
dann kenne ich sie in MyCompare nicht mehr. In MyCompare müsste ich dann mit einem Konstrukt wie
Delphi-Quellcode:
with List as TSortStringList do begin
.
.
.
end;
arbeiten, um doch an GetStartPos und GetNextPos zu kommen.

Für die vorab ermittelten Positionen brauche ich also entsprechende Attribute in der Klasse, in denen ich die Ergebnisse der Funktionen GetStartPos und GetNextPos vorhalte, die entsprechend Deinem Vorschlag vorher ermittelt wurden. Hier könnte dann ein dynamisches Array mit 'nem Record der Form
Delphi-Quellcode:
type
  rPosData = record
    StartPos : Word;
    NextPos : Word;
  end;
.
.
.
  fPosData = Array of rPosData;
.
.
.
herhalten und in
Delphi-Quellcode:
procedure TSortStringList.Compare;
Var
          i : Integer;
          iPos : Integer;
          iPosLast : Integer;
begin
  SetLength(fPosData,Self.Count);
  for i := 0 To Self.Count - 1 Do begin
    iPos := GetStartPos(Self[i],Self.Delimiter,fSortColumn);
    iPosLast := GetNextPos(Self[i],Self.Delimiter,iPos)
    fPosData[i].StartPos := iPos;
    fPosData[i].NextPos := iPosLast;
  end;
  Self.CustomSort(MyCompare);
end;
füllen wir das Array.
Als Ergebnis von MyCompare werden von CustomSort Einträge der Stringliste vertauscht. Wie bekomme ich denn da eine Synchronisation der vertauschen Einträge mit den vorab ermittelten Positionen hin? Dann müsste ich ja quasi in MyCompare so 'ne Art Swap für den Vertausch der zu Index1 und Index2 gehörenden Positionsangaben machen.

zu 3: Prinzipiell hast Du recht, eigentlich kann von "draussen" keiner an die Funktion ran, nur weitere Klassen innerhalb der gleichen Unit könnten Probleme bekommen. An dem Typecast selbst komme ich aber wohl nicht vorbei.

Momentan sieht das dann jetzt so aus:
Delphi-Quellcode:
type
  rPosData = record
    StartPos : Word;
    NextPos : Word;
  end;

  arPosData = Array of rPosData;

type
  tSortStringList = class(TStringList)
  private
    fSortColumn : Integer;
    fPosData : arPosData;
  protected
    function GetStartPos(s : String; Delimiter : Char; SortColumn : Integer) : Integer;
    function GetNextPos(s : String; Delimiter : Char; iStartPos : Integer) : Integer;
  public
    procedure Compare;
  published
    property SortColumn : Integer Read FSortColumn Write fSortColumn Default 0;
  end;
.
.
.
implementation
.
.
.
// Stelle im String ermitteln, ab der sortiert werden soll.
Function TSortStringList.GetStartPos(s : String; Delimiter : Char; SortColumn : Integer) : Integer;
Var
         iPos : Integer;
         iCount : Integer;
begin
  iPos := 0;
  for iCount := 1 to SortColumn Do iPos := PosEx(Delimiter,s,iPos + 1);
  Inc(iPos);
  Result := iPos;
end;

// Länge des zu sortierenden Strings ermitteln.
Function TSortStringList.GetNextPos(s : String; Delimiter : Char; iStartPos : Integer) : Integer;
Var
         iNextPos : Integer;
begin
  iNextPos := PosEx(Delimiter,s,iStartPos);
  case iNextPos of 0 : iNextPos := Length(s); end;
  Result := iNextPos;
end;

function MyCompare(List: TStringList; Index1, Index2: Integer): Integer;
var
         iPos : Integer;
begin
  with List As TSortStringList do begin
    if List.CaseSensitive then begin
      Result := AnsiCompareStr(Copy(List[Index1],
                                     fPosData[Index1].StartPos,
                                     fPosData[Index1].NextPos),
                                Copy(List[Index2],
                                     fPosData[Index2].StartPos,
                                     fPosData[Index2].NextPos)
                               );
    end else begin
      Result := AnsiCompareText(Copy(List[Index1],
                                      fPosData[Index1].StartPos,
                                      fPosData[Index1].NextPos),
                                 Copy(List[Index2],
                                      fPosData[Index2].StartPos,
                                      fPosData[Index2].NextPos)
                                );
    end;
    case Result of
      0 : ; // hier brauchen wir nichts tuten, beide String sind gleich
    else
      iPos := fPosData[Index1].StartPos;
      fPosData[Index1].StartPos := fPosData[Index2].StartPos;
      fPosData[Index2].StartPos := iPos;
      iPos := fPosData[Index1].NextPos;
      fPosData[Index1].NextPos := fPosData[Index2].NextPos;
      fPosData[Index2].NextPos := iPos;
    end;
  end;
end;

procedure TSortStringList.Compare;
Var
          i : Integer;
          iPos : Integer;
          iPosLast : Integer;
begin
  SetLength(fPosData,Self.Count);
  for i := 0 To Self.Count - 1 Do begin
    iPos := GetStartPos(Self[i],Self.Delimiter,fSortColumn);
    iPosLast := GetNextPos(Self[i],Self.Delimiter,iPos);
    fPosData[i].StartPos := iPos;
    fPosData[i].NextPos := iPosLast;
  end;
  Self.CustomSort(MyCompare);
end;


// Aufruf im Programm
procedure TForm1.Button1Click(Sender: TObject);
Var
          StringListe : TSortStringList;
begin
  Stringliste := TSortStringList.Create;
  Stringliste.LoadFromFile('20081010.log');
  Stringliste.Delimiter := '|';
  Stringliste.SortColumn := 1;
  Stringliste.CaseSensitive := false;
  Stringliste.Compare;
  StringListe.SaveToFile('20081010.log.Sort');
  Stringliste.Free;
end;
Geschwindigkeitstechnisch kann ich bei den kleinen Dateien, die ich momentan habe, keinen Unterschied merken, aber bei großen Mengen dürfte das schon was ausmachen.

Vielen Dank für Deine Ideen und Anregungen.
  Mit Zitat antworten Zitat