WICHTIG: Der Betrieb von goMatlab.de wird privat finanziert fortgesetzt. - Mehr Infos...

Mein MATLAB Forum - goMatlab.de

Mein MATLAB Forum

 
Gast > Registrieren       Autologin?   

Partner:




Forum
      Option
[Erweitert]
  • Diese Seite per Mail weiterempfehlen
     


Gehe zu:  
Neues Thema eröffnen Neue Antwort erstellen

Initialisierung von struct-arrays

 

Gast

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 31.10.2008, 12:37     Titel: Initialisierung von struct-arrays
  Antworten mit Zitat      
Hallo

ich möchte gerne eine Struktur folgender Form haben:

Test(:).x(:,:)
Test(:).y(:,:)

Das ganze soll vorher mit 0 Initialisiert werden, weil es ja von Matlab heißt, dass ein Aufbauen eines Arrays in einer Schleife zu lange dauert und man das vorher schonmal initialisiert haben soll.

Aber wie soll ich das ohne eine for-Schleife machen.

Mein Idee geht nur mit for-Schleife:

for q = 1 : 10
Test(q).x = zeros(5,4);
Test(q).y = zeros(5,4);
end

Weiß jemand etwas dazu?

Vielen Dank!!


katagent
Forum-Newbie

Forum-Newbie


Beiträge: 6
Anmeldedatum: 27.03.13
Wohnort: Hamburg
Version: 7.10.0
     Beitrag Verfasst am: 27.03.2013, 16:44     Titel:
  Antworten mit Zitat      
Moin,

ich habe/hatte ähnliches Problem:

Ich deklariere zunächst folgende Struktur:

Code:
z=struct(           ...
            't',0,   ...
            'p',0,  ...
            'h',0,  ...
            's',0,  ...
            'H',0,  ...
            'S',0,  ...
            'm',0,  ...
            'X',0,  ...
            'sal',0 ...        
        );


Danach habe ich 1x1 Struct. Ich weiß, dass ich davon 13 Stück brauchen werde, also machte ich daraus zunächst mit
Code:
z(13).t=0;

einen 1x13 struct array.

Das Problem: abgesehen von allen Feldern in z(1) und von einem Feld z(13).t enthielten alle Felder [] und keine Nullen.

Wenn man aber die Deklaration wie folgt verändert
Code:
z=struct(           ...
            't',{0 0 0 0 0 0 0 0 0 0 0 0 0},  ...
            'p',0,  ...
            'h',0,  ...
            's',0,  ...
            'H',0,  ...
            'S',0,  ...
            'm',0,  ...
            'X',0,  ...
            'sal',0 ...        
        );
 

dann hat man sofort einen 1x13 struct array mit Nullen in allen Feldern.

Was ist aber, wenn ich nicht 13, sonder 1300 structs haben will?
Dann muss es doch irgendwie anders gehen, als die Zeile mit 1300 Nullen {0 0 0 ....} zu schreiben?


.... Naja, beim Schreiben auch schon die Lösung gefunden:
Code:
cell(1x13);            %erstellt leeres 1x13 Cell
ans(:)={0};          %füllt es mit Nullen
z=struct(           ...
            't',ans,   ...
            'p',0,  ...
            'h',0,  ...
            's',0,  ...
            'H',0,  ...
            'S',0,  ...
            'm',0,  ...
            'X',0,  ...
            'sal',0 ...        
        );
 


Bei dir müsste es dann anstelle von meiner 13 deine Anzahl q, und anstelle von 0 jeweils zeros(5,4).

Grüße
Andi
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 28.03.2013, 00:09     Titel:
  Antworten mit Zitat      
Hallo katagent,
Zitat:
Bei dir müsste es dann anstelle von meiner 13 deine Anzahl q, und anstelle von 0 jeweils zeros(5,4).


Fast. Es liegt so haarscharf daneben, dass sich eine Diskussion lohnt:
Code:
c = cell(1, 1000);
c(:) = {zeros(5, 4)};

Damit könnte man nun ein Struct-Array initialisieren. Allerdings erzeugt dies nicht 1000 Matrizen, wie es für eine ordentliche Pre-allocierung ja notwendig wäre, sondern nur eine! Das Cell-Array "c" wird mit sogenannten Shared-Data-Copies gefüllte, also Variablen, die alle auf den gleichen Speicherbereich zeigen. Das ist auf Anhieb erst mal viel schneller und der Speicherbedarf ist deutlich kleiner. Aber sowie man die Werte ändert, ist zusätzlicher Aufwand nötig, um die Shared-Data-Copy per "Deep-Copying" in ein eigenständiges Array zu verwandeln. Dazu müssen Einträge in den Listen der Referenzen geändert werden, was zusätzliche Zeit beansprucht. Deswegen ist "c(:) = {zeros(10, 20)}" im Gegensatz zum ersten Anschein keine Pre-allocierung (oder wie sich dieses Wort auf Deutsch schreiben mag).

Verblüffend, oder? Und wie findet man das heraus?
Code:
format debug  % Nicht dokumentiert! Zeigt Meta-Infos an
c = cell(1, 2);
c(:) = {zeros(5, 4)};
c{1}
>> Structure address = 7d97028
  m = 10
  n = 20
  pr = 341e5d50
  pi = 0
  % ... und dann die vielen Nullen

c{2}
>> Structure address = 7d97028
  m = 10
  n = 20
  pr = 341e5d50
  pi = 0
  % ...

Wichtig sind hier die identischen "pr" Werte: Dies ist der Pointer zu den reellen Nutzdaten (pi ist 0, da keine imaginären Werte vorliegen). Beide Cell-Elemente verwenden also den gleichen Speicherbereich und das wird bei der Konstruktion des Structs auch weitergegeben. Sowie man dann schreibend darauf zugreift, werden die Daten zuerst dupliziert, was aber leider teuer ist.

Eine "richtige" Pre-allocation ist daher leider nur mit einer Schleife möglich:
Code:
c = cell(1, 1000);
for k = 1:1000
  c{k} = zeros(5, 4);
end

Dann kann man aber auch gleich in das Struct schreiben, was übrigens gar keine schlechte Lösung ist. Für die Orginal-Frage hieße dies:
Code:
Test = struct('x', cell(1, 10), 'y', []);
% Alternativ: Test = struct('x', cell(1, 10), 'y', cell(1,10));
% Damit wird "Test" pre-allociert!

for q = 1:10
  Test(q).x = zeros(5,4);
  Test(q).y = zeros(5,4);
end

Das ist meines Wissens nach tatsächlich der effizienteste Weg, die Arrays tatsächlich zu reservieren.
Besonders schnell ist das natürlich nicht, aber das liegt daran, dass hier eine ungeschickte Daten-Representation gewählt wurde. Ein einzelnes 3D-Array "zeros(5, 4, 10)" wäre deutlich schneller, aber man hätte nicht mehr die hübsche Aufteilung in ein Struct-Array.

Noch eine Bemerkung: Die explizite Verwendung von "ans" ist tückisch, weil es z.B. beim Debuggen zu anderen Ergebnissen führen kann. "ans" ist sehr "volatil" und man kann ein Überschreiben nicht garantiert verhindern. Also besser eine konkrete Variable verwenden:
Code:
c = cell(1, 13);      % Tippfehler: Nicht "(1x13)"
c(:)={0};          %füllt es mit Nullen
 

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
katagent
Forum-Newbie

Forum-Newbie


Beiträge: 6
Anmeldedatum: 27.03.13
Wohnort: Hamburg
Version: 7.10.0
     Beitrag Verfasst am: 28.03.2013, 01:07     Titel:
  Antworten mit Zitat      
Hallo Jan,

das ist in der Tat sehr heimtückisch. MatLab gaukelt da dem Nutzer etwas vor, was gar nicht gegeben ist Confused

Und ja, die Initialisierung mit einer Schleife kann man sich dann auch sparen.

Das, mit der ans-Variable hat mir auch MatLab gesagt. Kann denn diese ihren Wert ändern, selbst wenn die Code-Zeilen direkt hintereinander stehen?

Grüße
Andi
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 28.03.2013, 20:02     Titel:
  Antworten mit Zitat      
Hallo katagent,

"ans" enthält die letzte nicht in einer Variablen gespeicherte Rückgabe einer Funktion. Ich würde mich nicht darauf verlassen, dass z.B. ein TIMER Callback nicht unerwartet zwischen zwei Zeilen diese Variable überschreiben kann. Das wäre zwar ein exotischer Fall, aber falls er einträte kaum per Debugger zu finden, da er nicht reproduzierbar ist.
Das ist dann wie Autofahren ohne Sicherheitsgurt: In 99.99% aller Fälle passiert nix.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
katagent
Forum-Newbie

Forum-Newbie


Beiträge: 6
Anmeldedatum: 27.03.13
Wohnort: Hamburg
Version: 7.10.0
     Beitrag Verfasst am: 28.03.2013, 20:21     Titel:
  Antworten mit Zitat      
Hallo Jan S

Jan S hat Folgendes geschrieben:

Ich würde mich nicht darauf verlassen, dass z.B. ein TIMER Callback nicht unerwartet zwischen zwei Zeilen diese Variable überschreiben kann.
Gruß, Jan


Alles klar, mal wieder was Neues gelernt. Wusste nämlich gar nicht, dass es ihn überhaupt gibt.


Noch ein Nachtrag zum eigentlichen Thema:

Ich bin auf diese Seite gestoßen und derzufolge kann man mit
Code:
z(1:13) = struct( 't',0,   ...
            'p',0,  ...
            'h',0,  ...
            's',0,  ...
            'H',0,  ...
            'S',0,  ...
            'm',0,  ...
            'X',0,  ...
            'sal',0 ...        
        );

sauber ein struct array preallozieren. Stimmt es oder wird hier von MatLab wieder ein bisschen getrickst?

Weiter unten wird auch eine ineffiziente Variante beschrieben, ähnlich wie du sie mit Shared-Data-Copies erwähnt hast.

Grüße
Andi
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 28.03.2013, 21:49     Titel:
  Antworten mit Zitat      
Hallo katagent,

Der gezeigte Code pre-allociert das skalare Struct einwandfrei.
Man muss hier nun unterscheiden, ob das Struct-Array selbst pre-allociert wird, also alle Felder und die entgültige Größe definiert wird, oder aber die Arrays, die in den Feldern stehen! Das ist ein Unterschied.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Neues Thema eröffnen Neue Antwort erstellen



Einstellungen und Berechtigungen
Beiträge der letzten Zeit anzeigen:

Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum posten
Du kannst Dateien in diesem Forum herunterladen
.





 Impressum  | Nutzungsbedingungen  | Datenschutz | FAQ | goMatlab RSS Button RSS

Hosted by:


Copyright © 2007 - 2025 goMatlab.de | Dies ist keine offizielle Website der Firma The Mathworks

MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.