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

Multi-level struct array zusammenfassen

 

KaiS
Forum-Century

Forum-Century


Beiträge: 102
Anmeldedatum: 19.04.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 07.06.2013, 00:27     Titel: Multi-level struct array zusammenfassen
  Antworten mit Zitat      
Hallo zusammen,

ich hätte folgendes Beispiel:

Code:

test(1).data(1).x = 1
test(1).data(2).x = 2
test(2).data(1).x = 3
test(2).data(2).x = 5
test(2).data(3).x = 4
 


Nun möchte ich einen Array kreieren, welches die Werte des Structs hintereinander herausgibt, also z.B.

Code:
test_array = [1, 2, 3, 5, 4]


Würde mein struct array keine verschiedenen ".data"-Felder haben, sondern nur test.x sein, dann könnte ich das einfach per

Code:
test_array = [test(:).x]


bewerkstelligen. Aber ähnliches funktioniert leider in meinem angesprochenen Beispiel nicht mehr.

Weiß da jmd weiter?

Vielen Dank!

LG
Kai
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: 07.06.2013, 08:59     Titel: Re: Multi-level struct array zusammenfassen
  Antworten mit Zitat      
Hallo KaiS,

Du hast es ganz richtig bemerkt: Das geht in Matlab nicht. Für Deine Absicht ist die gewählte Representation der Daten als geschachtelter Struct einfach ungeeignet.

Die Wahl einer Daten-Struktur ist ein nicht-trivialer Teil des Programmdesigns, bei der Erfahrung und handwerkliches Geschick wichtig sind. Oft gilt es einen Kompromiss aus Übersichtlichkeit (reduziert Programmier- und Debug-Zeit) und Effizienz (reduziert Laufzeit) zu finden.

Der geschachtelte Struct kann nur per Schleife in ein Array umgewandelt werden. Deshalb würde ich empfehlen, die Struktur zu ändern. Falls das nicht geht:
Code:
nTest = numel(test);
C = cell(nTest, 1);
for iTest = 1:nTest
  C{iTest} = [test(iTest).data.x];  % BUGFIX
end
Result = cat(2, C{:});
% BUGFIX
Gruß, Jan

Zuletzt bearbeitet von Jan S am 07.06.2013, 21:31, insgesamt einmal bearbeitet
Private Nachricht senden Benutzer-Profile anzeigen
 
KaiS
Themenstarter

Forum-Century

Forum-Century


Beiträge: 102
Anmeldedatum: 19.04.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 07.06.2013, 09:54     Titel:
  Antworten mit Zitat      
Hi Jan,

danke für den Codevorschlag! Die Struktur kann ich leider nicht ändern bzw. tue es nur sehr ungern, weil da noch ein paar andere Rattenschwänze dranhängen.

Kann es sein, dass dir in der 4. Zeile beim Setzen der runden Klammer ein Fehler unterlaufen ist? Die runde Klammer soll ja wahrsch nach iTest enden, oder?

Wie passe ich den Code an, wenn nicht nur test(i) sich ändert, sondern innerhalb jedes test(i) auch noch das data unterteilt ist, d.h. test(i).data(j).x?

Danke!

LG
Kai
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: 07.06.2013, 21:50     Titel:
  Antworten mit Zitat      
Hallo Kai,

Ja, da waren zwei Bugs im Code. Es ist etwas ungeschickt, dass ich oft kein Matlab zur Verfügung habe um meine Code-Vorschläge laufen lassen zu können. Siehe BUGFIXes im Code.

Ich verstehe gut, dass Du die Struktur der Daten kaum noch ändern kannst. Das kommt häufig vor. Bei größeren Programmier-Projekten ist das sogar eher der Standard. Deswegen gibt es dann regelmäßig Revisionen, bei denen alter Code gnadenlos in die Tonne gehauen wird, um wieder eine klare und effiziente Daten-Struktur zu erhalten.
Bekannt ist das z.B. bei Apples drastischen inkompatibelen Schnitten bei neuen Versionen des MacOS. Windows dagegen pfriemelt in manchen Ecken seines Windows 2012 Servers immer noch mit Code herum, der für Windows95 geschrieben wurde. Tja.

Zitat:
Wie passe ich den Code an, wenn nicht nur test(i) sich ändert, sondern innerhalb jedes test(i) auch noch das data unterteilt ist, d.h. test(i).data(j).x?

Aber das ist doch bereits der Fall!? Das am tiefsten verschachtelte Struct-Array kann automatisch zusammengefasst werden, alle davor benötigen eine extra Schleife.
Code:
s(:).t(:).u(:).v(:).x = 1;  % Pseudo-code !!!
C = cell(1, n1*n2*n3*n4);
index = 0;
for i1 = 1:n1
  for i2 = 1:n2
    for i3 = 1:n3
       index = index + 1;
       C{index} = [s(i1).t(i2).u(i3).v(:).x];
    end
  end
end

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
KaiS
Themenstarter

Forum-Century

Forum-Century


Beiträge: 102
Anmeldedatum: 19.04.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 09.06.2013, 23:25     Titel:
  Antworten mit Zitat      
Hi Jan,

sorry erstmal für die späte Antwort.

Ich habe deinen Code ein bisschen auf mein Problem angepasst, weil dein n2 bei mir variabel ist (jedes struct hat also unterschiedlich viele Unterfelder).

Code:
index = 0;
for f = 1:length(test.element)
    for g = 1:length(test.reaction)
        for h = 1:length(test.reaction(g).educt)
            if strcmp(test.element(f).id, test.reaction(f).educt{g})
                index = index + 1;
                educt_init_conc{index} = [test.reaction(f).educt{g}.conc];
                break;
            end
        end
    end
end
 


Zur Erklärung: Ich habe chemische Reaktionen, wo die Edukte und Produkte in verschiedenen Variablen abgespeichert sind.
In test.element ist hierbei im Unterfeld .id je ein unterschiedlicher String hinterlegt, welches den jeweiligen Namen des chemischen Elements darstellt.

Nun habe ich zusätzlich test.reaction, welches als eine Art Datenbank fungiert, wo sämtliche Werte gespeichert sind.
Von test.reaction will ich je nachdem welche Elemente in test.element erhalten sind, die Konzentration dieser Elemente herausfinden. D.h. meine Idee war, mit strcmp die Edukte jeder einzelnen Reaktion abzusuchen bis das Edukt erreicht ist, welches ich in test.element suche. Habe ich den passenden Eintrag in test.reaction().educt() gefunden, so kann ich einfach deren Konzentration (test.reaction().educt().conc) einer neuen Variablen zuweisen (in meinem Fall "educt_init_conc").

Nun habe ich aber zwei Probleme:

1. Das von dir vorgeschlagene
Code:
C = cell(1, n1*n2*n3*n4);
funktioniert in meinem Fall nicht, da n2 variabel ist und von n1 abhängt.
Aber muss ich meine Zelle überhaupt initialisieren? Reicht es nicht, einfach die jeweiligen Werte einem aufsteigenden Index zuzuweisen?

2. In meinem Code habe ich in der if-Bedingung ein break eingebaut, da ja sobald ein Element gefunden wurde nicht mehr weiter gesucht werden muss. Dieses break soll sich aber deswegen eigentlich auf die for-Schleifen mit g und h als Laufvariablen beziehen. Im Moment würde ich bei break aber nur die for-Schleife mit h beenden.
Gibt es eine Möglichkeit wie ich bei Erfüllung der if-Bedingung die letzten beiden for-Schleifen beende und somit wieder bei der ersten for-Schleife lande?
Ich hoffe ich habe mich nicht zu kompliziert ausgedrückt.. Smile

Danke!
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: 10.06.2013, 00:59     Titel:
  Antworten mit Zitat      
Hallo Kai,

Man kann das Resultat schon iterativ wachsen lassen. Aber das wird bei größeren Arrays sehr ineffizient. dabei wird nämlich in jeder Iteration ein neues Array angelegt und die alten Daten kopiert. Bei 1000 Elementen im Ergebnis sind das SUM(1:1000)=500500 Elemente, die Reserviert und kopiert werden müssen, und die Anzahl wächst mit dem Quadrat der Größe des Outputs.
Also ist eine Pre-allocation immer und unbedingt empfohlen. Lieber zu groß als zu klein.


Code:

educt_init_conc = cell(1, 1e6);
index = 0;
for f = 1:length(test.element)
    isBroken = false;
    for g = 1:length(test.reaction)
        for h = 1:length(test.reaction(g).educt)
            if strcmp(test.element(f).id, test.reaction(f).educt{g})
                index = index + 1;
                educt_init_conc{index} = [test.reaction(f).educt{g}.conc];
                isBroken = true;
                break;
            end
        end
        if isBroken
          break;
        end
    end
end
 

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
KaiS
Themenstarter

Forum-Century

Forum-Century


Beiträge: 102
Anmeldedatum: 19.04.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 10.06.2013, 08:18     Titel:
  Antworten mit Zitat      
Hi Jan,

ich habe gerade keinen Zugriff auf mein Matlab, aber der Vorschlag von dir sieht sehr gut aus! Ich werde es heute Abend mal ausprobieren.

Vielen Dank!

LG
Kai
Private Nachricht senden Benutzer-Profile anzeigen
 
KaiS
Themenstarter

Forum-Century

Forum-Century


Beiträge: 102
Anmeldedatum: 19.04.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 13.06.2013, 22:26     Titel:
  Antworten mit Zitat      
Es hat übrigens funktioniert! Danke nochmal! Smile
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 - 2024 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.