Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Mehrdimensionaler Array wie in PHP möglich? (https://www.delphipraxis.net/156062-mehrdimensionaler-array-wie-php-moeglich.html)

torud 18. Nov 2010 13:06

Mehrdimensionaler Array wie in PHP möglich?
 
Hallo Wissende,

ich bin gerade dabei eine Tabellenberechnung für eine Sportart aus php nach Delphi zu portieren. In der mir vorliegenden Source wird mit mehrdimensionalen Arrays gearbeitet. Nun bin ich am Grübeln, wie ich das am cleversten übersetze.

Hier mal ein Fetzen aus der Source:
Delphi-Quellcode:
$results[$team_a_id]['punkte'] += $pts_g;
$results[$team_b_id]['punkte'] += $pts_v;
$results[$team_a_id]['siege']   += 1;
$results[$team_b_id]['verloren'] += 1;
$results ist ein mehrdimensionales Array
$team_a_id ist eine Variable, die die Team-Id des Teams A beinhaltet
$team_b_id ist eine Variable, die die Team-Id des Teams B beinhaltet
'punkte' steht für die Punkte, die es bei einem Sieg gibt
usw

Nun kann ich ja sicher in Delphi keinen solchen Array erzeugen, bei dem ich die Inhalte über die Namen anspreche. Durch ein Array iteriert man doch immer über einen Index. Oder?

Ich schwanke nun, ob ich einen Mehrdimensionalen Array benutzen soll oder mir ein Record bastle. Dabei Frage ich mich natürlich auch, wie ich dann zum Beispiel später die Einträge nach den Punkten der Teams aufsteigend sortieren kann (Array/Record) und wie ich einen Teameintrag später noch ansprechen kann, ohne jedes mal komplett durch das Array/Record über eine Schleife, in der ich die jeweilge Team-Id prüfe, ansprechen kann.

Für helfende Infos bedanke ich mich im voraus. Sollte mehr Sourcecode benötigt werden, stelle ich auch gern mehr zur Verfügung.

ChrisE 18. Nov 2010 13:17

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Hallo,

eine Array of Record. Wobei der Index im Array Deine Team_ID ist und das Record die benötigten Informationen bereit hält.

Du kannst auch eine TList verwenden mit Klassen die deine Information bereit hält. Dort kannst du dann ein Customsort durchführen. Die Methode must du selber implementieren. Sie gibt dir immer zwei Listen-Elemente und du muss sagen welches vor dem anderen sein soll.

Gruß, Chris

Hansa 18. Nov 2010 13:19

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Delphi-Quellcode:
array [1..2,1..3,1..10] of ...
Das wäre jetzt dreidimensional.

DeddyH 18. Nov 2010 13:29

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Man kann auch solche Konstrukte verwenden, solange man die Übersicht behält (was nicht immer ganz einfach ist):
Delphi-Quellcode:
type
  TKategorie = (Punkte,Siege,verloren);
  TKatArray = array[TKategorie] of integer;
  TDynArray = array of TKatArray;


procedure TfrmTest.FormCreate(Sender: TObject);
var Arr: TDynArray;
    i: integer;
begin
  SetLength(Arr,2);
  Arr[0][Punkte] := 1;
  Arr[0][Siege] := 0;
  Arr[0][verloren] := 0;
  Arr[1][Punkte] := 3;
  Arr[1][Siege] := 1;
  Arr[1][verloren] := 0;
  for i := Low(Arr) to High(Arr) do
    ShowMessage(Format('Punkte: %d, Siege: %d, verloren: %d',[Arr[i][punkte],Arr[i][Siege],Arr[i][verloren]]));
  SetLength(Arr,0);
end;

himitsu 18. Nov 2010 15:12

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Delphi-Quellcode:
variable['text']
.
sowas nennt sich assoziatives Array

für kann man eine TStringList mißbauchen
- wenn Stringvalue: Name > Value (Strings = 'Name=Value')
- Strings/Zeile = Name und den Value ins Objekt

oder einfach mal nach Hier im Forum suchenassoziatives, Hier im Forum suchenassoziativ oder Hier im Forum suchenAssocArray

implementation 18. Nov 2010 16:06

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Oder ein Dictionary / HashTable :gruebel:

torud 20. Nov 2010 23:22

AW: Mehrdimensionaler Array wie in PHP möglich?
 
Hallo Wissende,

ich habe es nun einigermaßen erfolgreich von php nach Delphi übersetzen können, indem ich eine Stringlist mit Objekten befülle. Das klappt soweit ganz gut. Nun habe ich aber noch das Problem des Sortierens und des direkten Vergleichs bei Punktgleicheit.

Hier mal mein Code für einen prüfenden Blick. Ist zum Teil kommentiert. Ich stehe natürlich für Rückfragen zur Verfügung:

Delphi-Quellcode:
//dies ist die klasse für das erzeugen der objekte für die stringliste
unit rank_data;

interface

uses
  classes, XmlIntf, SysUtils, Variants;

type
  TRankData=class
  public
    TeamName   : String;
    Won        : Integer;
    Loss       : Integer;
    Draw       : Integer;
    Points     : Integer;
    Goals      : Integer;
    Goals_Away : Integer;
    ReGoals    : Integer;
    DirGoals   : Integer;
    Games      : Integer;
    constructor Create(aName,anId: String); overload;
    constructor Create; overload;
  end;

implementation

{ TRankData }

constructor TRankData.Create(aName, anId: String);
begin
  inherited Create;
  TeamName := aName;

end;

constructor TRankData.Create;
begin
  inherited;
end;

end.
Delphi-Quellcode:
//hier die prozedure, welche die daten aus db ausliest und in eine stringlist schreibt
procedure TForm1.btn_calculateClick(Sender: TObject);
var
  int_pts_g, int_pts_u, int_pts_v, int_pts_vl, i : integer;
  str_league_id, str_round : String;
  str_TName_a, str_TName_b : String;
  str_team_a_id, str_team_b_id : String;
  int_result_a, int_result_b, int_end_periode : integer;
  var_holder : Variant;
  RankDataA, RankDataB : TRankData;
  intListPosA, intListPosB : integer;
begin
  //globale rankliste leeren->berücksichtigt nicht die schon vorhandenen objekte
  RankList.Clear;
  //besorgen des spieltages BIS zu dem berechnet werden soll
  if not(cmb_calc_from.Text <> '') and not(cmb_calc_to.Text <> '') then
    begin
      MessageDlg('Please select Round From and Round To!',mtInformation,[mbok],0);
      exit;
    end;
  //internes beschaffen der league_id und round
  str_league_id := sel_match.GetLeagueIdByLeagueName(cmb_leagues.Text);
  str_round    := cmb_calc_to.Text;

   // step 1: lade die wertigkeiten - kann man noch optimieren
   //wir holen uns die wertigkeit eines spieles aus der db
  with dm.ADOQuery1 do
    begin
      Close;
      sql.Clear;
      sql.Add('SELECT * FROM leagues WHERE id=' + str_league_id);
      Open;
      ExecSQL;
      var_holder:= FieldbyName('pts_won').AsVariant;
      int_pts_g := VarToIntDef(var_holder, 0);
      var_holder:= FieldbyName('pts_draw').AsVariant;
      int_pts_u := VarToIntDef(var_holder, 0);
      var_holder:= FieldbyName('pts_loss').AsVariant;
      int_pts_v := VarToIntDef(var_holder, 0);

      // step 2: lade alle ergebnisse bis zum entsprechenden spieltag und die teamnamen gleich dazu
      Close;
      sql.Clear;
      sql.Add('SELECT r.league_id, r.season_id, r.round, r.team_a_id, r.team_b_id, r.result_a, r.result_b, end_in_periode ' +
            'FROM matches r, teams t_a, teams t_b ' +
            'WHERE r.league_id = ' + str_league_id +
               ' AND r.season_id = 6' +
               ' AND r.round <= ' + str_round +
               ' AND r.result_a > -1' +
               ' AND r.result_b > -1' +
               ' AND r.team_a_id = t_a.id' +
               ' AND r.team_b_id = t_b.id' +
            ' ORDER BY r.round');
      Open;
      ExecSQL;

      while not(Eof) do begin
        // lokale variablen
        int_pts_vl := 0; //punkte verloren für schleife reseten
        str_team_a_id := FieldbyName('team_a_id').AsString;
        str_team_b_id := FieldbyName('team_b_id').AsString;
        int_result_a := FieldbyName('result_a').AsInteger;
        int_result_b := FieldbyName('result_b').AsInteger;
        str_TName_a  := sel_match.GetTeamNameById(str_team_a_id);
        str_TName_b  := sel_match.GetTeamNameById(str_team_b_id);
        var_holder   := FieldbyName('end_in_periode').AsVariant;
        int_end_periode := VarToIntDef(var_holder, 0);
        //bei verloren nach verlängerung gibts trotzdem 1 punkt!!!
        case int_end_periode of
          0,1,2,3 : int_pts_vl := int_pts_v;
          else     int_pts_vl := int_pts_v + 1;
        end;

        if not(RankList.IndexOf(str_team_a_id) > -1) then
          begin
            RankDataA := TRankData.Create(str_TName_a,str_team_a_id);
            //intListPosA := RankList.Add(str_team_a_id);
            intListPosA := RankList.AddObject(str_team_a_id, RankDataA);
          end
        else
          RankDataA := (RankList.Objects[RankList.IndexOf(str_team_a_id)] as TRankData);

        if not(RankList.IndexOf(str_team_b_id) > -1) then
          begin
            RankDataB := TRankData.Create(str_TName_b,str_team_b_id);
            //intListPosA := RankList.Add(str_team_a_id);
            intListPosB := RankList.AddObject(str_team_b_id, RankDataB);
          end
        else
          RankDataB := (RankList.Objects[RankList.IndexOf(str_team_b_id)] as TRankData);

        //punkte, gewonnen, verloren, unentschieden sammeln
        if (int_result_a > int_result_b) then //team a hat gewonnen
          begin
            RankDataA.Points := RankDataA.Points + int_pts_g;
            RankDataB.Points := RankDataB.Points + int_pts_vl;
            RankDataA.Won   := RankDataA.Won + 1;
            RankDataB.Loss  := RankDataB.Loss + 1;
          end
        else if (int_result_a < int_result_b) then //team b hat gewonnen
          begin
            RankDataB.Points := RankDataB.Points + int_pts_g;
            RankDataA.Points := RankDataA.Points + int_pts_vl;
            RankDataB.Won   := RankDataB.Won + 1;
            RankDataA.Loss  := RankDataA.Loss + 1;
          end
        else // bleibt unentschieden
          begin
            RankDataB.Points := RankDataB.Points + int_pts_u;
            RankDataA.Points := RankDataA.Points + int_pts_u;
            RankDataB.Draw  := RankDataB.Draw + 1;
            RankDataA.Draw  := RankDataA.Draw + 1;
          end;

          //tore geschossen, erhalten und auswärts
          RankDataA.Goals := RankDataA.Goals + int_result_a;
          RankDataB.Goals := RankDataB.Goals + int_result_b;
          RankDataA.ReGoals := RankDataA.ReGoals + int_result_b;
          RankDataB.ReGoals := RankDataB.ReGoals + int_result_a;
          RankDataB.Goals_Away := RankDataB.Goals_Away + int_result_b;
          //tore gegen die andere mannschaft (wichtig für direkten vergleich)
          //hierzu fehlt mir leider noch eine idee zum übersetzen!!!
          //$results[$team_a_id]['gegen_team'][$team_b_id]['tore_heim'] = $result_a;
          //$results[$team_b_id]['gegen_team'][$team_a_id]['tore_ausw'] = $result_b;
          //spiele
          RankDataA.Games := RankDataA.Games + 1;
          RankDataB.Games := RankDataB.Games + 1;

        Next;
      end;
    end;
    //debugging der datenlage
    TabString.Clear;
    for i := 0 to RankList.Count -1 do
      begin
        TabString.Add(RankList.Strings[i]+' - Team: '+
          (RankList.Objects[i] as TRankData).TeamName +
          ' - Points: ' + inttostr((RankList.Objects[i] as TRankData).Points) +
          ' - Goals: ' + inttostr((RankList.Objects[i] as TRankData).Goals) +
          ' - RGoals: ' + inttostr((RankList.Objects[i] as TRankData).ReGoals) +
          ' - Games: ' + inttostr((RankList.Objects[i] as TRankData).Games));
      end;

    ShowMessage(TabString.Text);
end;
Hier noch das Ausgabeergebnis meiner ShowMessage, welches inhaltlich korrekt aber leider noch nicht sortiert ist:
TeamID - Teamname - Punkte - erzielte Tore - erhaltene Tore - gespielte Spiele
2383 - Team: Switzerland - Points: 6 - Goals: 4 - RGoals: 1 - Games: 2
2384 - Team: Slovakia - Points: 3 - Goals: 3 - RGoals: 4 - Games: 2
2381 - Team: Germany - Points: 4 - Goals: 6 - RGoals: 6 - Games: 2
2382 - Team: Canada - Points: 2 - Goals: 4 - RGoals: 6 - Games: 2

Wie in der Ausgabe auffällt ist da noch nichts sortiert. In der Stringliste selbst stehen nur die TeamId´s. In den dazugehörenden Objekten sind dann die Daten vorrätig.

Dann würde ich noch gern wissen, ob es reicht einfach nur die Stringliste zu "Clearen", um auch die daran hängenden Objekte freizugeben!??


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz