Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Dimensionen eines mehrdimensionalen Array ermittlen?


Daniel L. - Sa 08.12.12 18:59
Titel: Dimensionen eines mehrdimensionalen Array ermittlen?
Hallo,


lässt sich die Zahl der Dimensionen eines dynamischen - mehrdimensionalen Array irgendwie ermitteln?

Gruss: Daniel

Moderiert von user profile iconNarses: Titel geändert.


Mathematiker - Sa 08.12.12 20:21

Hallo,
zum Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
    setlength(x,a,b);
    ... 
    dimension1:=length(x);
    dimension2:=length(x[0]);

In dimension1 steht der Wert a, in dimension2 das b und für mehr Dimensionen entsprechend weiter.

Beste Grüße
Mathematiker


jaenicke - Sa 08.12.12 20:32

Wobei die Unterarrays ja auch verschieden groß sein können. Und dann muss man natürlich auch einzeln prüfen, ob das Array, dessen Element geprüft werden soll, auch groß genug ist. (Length auf ein nicht existentes Arrayelement gibt eine Zugriffsverletzung.)


Delphi-Laie - Sa 08.12.12 20:46

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
zum Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
    setlength(x,a,b);
    ... 
    dimension1:=length(x);
    dimension2:=length(x[0]);

In dimension1 steht der Wert a, in dimension2 das b und für mehr Dimensionen entsprechend weiter.

Beste Grüße
Mathematiker


Müßte das nicht in eine Kopf- oder Fußschleife inkl. eines Fehlerbehandlungscodes (s. jaenickes Beitrag) gepackt werden? Es geht ja schließlich darum, die Anzahl der Dimensionen zu ermitteln?!

Ergänzung: Problematisch wird das auch vor der Dimensionierung. Deklariert ist das Array ja schon mit soundsoviel Dimensionen. Es scheint mir, als müßten vor diesen dimensionsbezogenen Abfragen die einzelnen Dimensionen erst einmal (mit Setlength) dimensioniert werden (welch ein herrlicher verbaler, aber nicht inhaltlicher Pleonasmus).

Ergänzung 2: Ist mit einer Schleife wohl nicht hinzubekommen. Wie will man length(a), length(a[0]), length(a[0,0]) usw., also den Inhalt in den eckigen Klammern, systematisch aufbauen und vergrößern, bis sich eine Exzeption ergibt?


jaenicke - Sa 08.12.12 22:09

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Ergänzung: Problematisch wird das auch vor der Dimensionierung. Deklariert ist das Array ja schon mit soundsoviel Dimensionen. Es scheint mir, als müßten vor diesen dimensionsbezogenen Abfragen die einzelnen Dimensionen erst einmal (mit Setlength) dimensioniert werden (welch ein herrlicher verbaler, aber nicht inhaltlicher Pleonasmus).
Nein, du kannst die Unterarrays auch alle gleich groß machen, indem du SetLength entsprechend viele Parameter übergibst.
Du kannst sie aber auch einzeln und auch verschieden setzen.


Mathematiker - Sa 08.12.12 23:17

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Es geht ja schließlich darum, die Anzahl der Dimensionen zu ermitteln?!

Richtig, so lautet die Frage. Habe ich nicht richtig gelesen und folglich falsch beantwortet.

Allerdings ergibt sich für mich dann die Frage, wozu man das eigentlich braucht? :nixweiss:
Gibt es denn überhaupt die Möglichkeit, dass sich ein dynamisches Array selbst Dimensionen hinzufügen kann, ohne dass ich es "merke"?
Oder geht es hier darum, die Daten aus einer fremden Quelle, deren Struktur unbekannt ist, auszulesen?

Beste Grüße
Mathematiker


Daniel L. - So 09.12.12 02:07

Also ich will als Variant - Parameter an ein Funktion beliebige dynamische Arrays übergeben


Delphi-Quelltext
1:
function sort (V : variant) : variant;                    


Die Funktion muss zuersteinmal die Anzahl der Dimensionen ermitteln.
Jetzt ist mir eingefallen: ich kann ja die Anzahl der Dimensionen als zusätzlichen Parameter
mitübergeben :wink:
Problem hat sich so erledigt.

Daniel


Delphi-Laie - So 09.12.12 14:59

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Es geht ja schließlich darum, die Anzahl der Dimensionen zu ermitteln?!

Richtig, so lautet die Frage. Habe ich nicht richtig gelesen und folglich falsch beantwortet.

Allerdings ergibt sich für mich dann die Frage, wozu man das eigentlich braucht? :nixweiss:


Nun, man kann sie m.e. jedenfalls nicht mit den Sprachumfang des Delphis ermitteln: Wollte man mit seltlength(a), setlength(a[0], setlength(a[0,0] oder auch nur mit der Adressierung a[0], a[0,0], in einer try-Answeisung, das ermitteln so scheitert das schon bei der Syntaxprüfung, wenn die Anzahl der deklarierten Dimensionen überschritten wird. Hinzu kommt, das schrieb ich schon oben, daß man die mit der Anzahl der Dimensionen mitwachsenden Indizes [0], [0,0], [0,0,0] usw. nicht in Form einer Schleife wachsen lassen kann, man müßte es explizieren, und dann wären verdammt viele Dimensionen zu beachten.

Kurzum, was durch den Quelltext deklariert und damit fix(iert) ist, bedarf keiner Ermittlung zur Laufzeit.

Auch bei der Übergabe eines Arrays als Parameter sind n.m.w. zwar die Anzahl der Elemente pro Dimension, nicht jedoch die Anzahl der Dimensionen variabel.

Edit: Las soeben erst Daniels Beitrag. Also, mit variant würde ich ohnehin nie "rummachen", jedenfalls nicht ohne Notwendigkeit, und vor einer solchen stand ich noch nie.


bummi - So 09.12.12 19:06

Da bei Variants fast alles möglich ist, dürfte die Übergabe der Anzahl nicht ausreichen.

QuickAndDirty-Beispiel wie man an die Infos kommt.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
Function Sort(va:Variant):Variant;
begin
  if VarIsArray(va)  then
    Showmessage(IntToStr( VarArrayHighBound(va[3],1)));

end;

procedure TForm6.Button1Click(Sender: TObject);
var
 a:Variant;
 b:Variant;
begin

   b := VarArrayOf([1,2,3,'test']);
   a := VarArrayOf(['Nase',17,'bär',b]);
   Sort(a);
end;


Gerd Kayser - Mo 10.12.12 04:28

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Auch bei der Übergabe eines Arrays als Parameter sind n.m.w. zwar die Anzahl der Elemente pro Dimension, nicht jedoch die Anzahl der Dimensionen variabel.

Die definierten Dimensionen nicht, aber die benutzten. Zum Ausprobieren kannst Du ja mal die beiden letzten SetLength-Anweisungen im Beispiel mit einem dreidimensionalen Array auskommentieren. Man kann das Beispiel sicherlich noch optimieren.


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:
procedure TMainform.Button1Click(Sender: TObject);
var
  TestArray : Array of Array of Array of Integer;
  Schleife  : Integer;
  Schleife1 : Integer;
  Zahl      : Integer;
  Dimension : Integer;
  Dimension1: Integer;
  Dimension2: Integer;
  Dimension3: Integer;
begin
  Memo1.Clear;

  // Zum Testen ggf. einzelne Zeilen auskommentieren.
  SetLength(TestArray, 5);
  SetLength(TestArray[0], 1);
  SetLength(TestArray[1], 3);
  SetLength(TestArray[12], 4);
  SetLength(TestArray[2], 7);
  SetLength(TestArray[3], 5);
  SetLength(TestArray[4], 7);
  SetLength(TestArray[12], 4);
  SetLength(TestArray[46], 7);

  Dimension1 := 0;
  Dimension2 := 0;
  Dimension3 := 0;

  if (Length(TestArray) - High(TestArray) = 1then
    Memo1.Lines.Add('dynamisches Array');

  Dimension := 0;

  // Elemente der 1. Dimension
  Zahl := Length(TestArray);
  if Zahl > 0 then
    Dimension1 := 1;

  // Elemente der 2. Dimension
  for Schleife := 0 to High(TestArray) do
    begin
      Zahl := Zahl + Length(TestArray[Schleife]);
      // Elemente der 3. Dimension
      if Length(TestArray[Schleife]) > 0 then
        begin
          Dimension2 := 1;
          for Schleife1 := 0 to High(TestArray[Schleife]) do
            begin
              Zahl := Zahl + Length(TestArray[Schleife, Schleife1]);
              if Length(TestArray[Schleife, Schleife1]) > 0 then
                Dimension3 := 1;
            end;
        end;
    end;
  Memo1.Lines.Add('Anzahl Elemente: ' + IntToStr(Zahl));
  Dimension := Dimension1 + Dimension2 + Dimension3;
  Memo1.Lines.Add('Anzahl benutzte Dimensionen: ' + IntToStr(Dimension));
  TestArray := nil;
end;

procedure TMainform.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown := true;
end;