Suche…


Nützliche Funktionen für Zellen und Arrays

In diesem einfachen Beispiel werden einige Funktionen erläutert, die ich seit der Verwendung von MATLAB als äußerst nützlich cellfun : cellfun , arrayfun . Die Idee ist, eine Array- oder Zellklassenvariable zu verwenden, alle Elemente zu durchlaufen und auf jedes Element eine eigene Funktion anzuwenden. Eine angewendete Funktion kann entweder anonym sein, was normalerweise ein Fall ist, oder jede reguläre Funktion, die in einer * .m-Datei definiert ist.

Beginnen wir mit einem einfachen Problem und sagen wir müssen eine Liste von * .mat-Dateien finden, die den Ordner enthalten. In diesem Beispiel erstellen wir zunächst einige * .mat-Dateien in einem aktuellen Ordner:

for n=1:10; save(sprintf('mymatfile%d.mat',n)); end

Nach der Ausführung des Codes sollten 10 neue Dateien mit der Erweiterung * .mat vorhanden sein. Wenn wir einen Befehl ausführen, um alle * .mat-Dateien aufzulisten, z. B .:

mydir = dir('*.mat');

wir sollten ein Array von Elementen einer dir-Struktur erhalten; MATLAB sollte eine ähnliche Ausgabe wie diese liefern:

10x1 struct array with fields:
    name
    date
    bytes
    isdir
    datenum

Wie Sie sehen, ist jedes Element dieses Arrays eine Struktur mit Feldern. Alle Informationen sind in der Tat für jede Datei wichtig, aber in 99% interessiere ich mich eher für Dateinamen und nichts anderes. Um Informationen aus einem Struktur-Array zu extrahieren, habe ich eine lokale Funktion erstellt, die temporäre Variablen der richtigen Größe für Schleifen erstellt, aus jedem Element einen Namen extrahiert und in der erstellten Variablen speichert. Eine viel einfachere Möglichkeit, genau das gleiche Ergebnis zu erzielen, ist die Verwendung einer der oben genannten Funktionen:

mydirlist = arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false)
mydirlist = 
    'mymatfile1.mat'
    'mymatfile10.mat'
    'mymatfile2.mat'
    'mymatfile3.mat'
    'mymatfile4.mat'
    'mymatfile5.mat'
    'mymatfile6.mat'
    'mymatfile7.mat'
    'mymatfile8.mat'
    'mymatfile9.mat'

Wie funktioniert diese Funktion? Normalerweise sind zwei Parameter erforderlich: ein Funktionshandle als erster Parameter und ein Array. Eine Funktion bearbeitet dann jedes Element eines gegebenen Arrays. Der dritte und der vierte Parameter sind optional, aber wichtig. Wenn wir wissen, dass eine Ausgabe nicht regelmäßig ist, muss sie in der Zelle gespeichert werden. Dies muss darauf hingewiesen werden, dass für UniformOutput die Einstellung false UniformOutput . Standardmäßig versucht diese Funktion, eine reguläre Ausgabe, z. B. einen Zahlenvektor, zurückzugeben. Lassen Sie uns zum Beispiel Informationen darüber gewinnen, wie viel Speicherplatz von jeder Datei in Bytes beansprucht wird:

mydirbytes = arrayfun(@(x) x.bytes, dir('*.mat'))
mydirbytes =
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560

oder Kilobytes:

mydirbytes = arrayfun(@(x) x.bytes/1024, dir('*.mat'))
mydirbytes =
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500

Diesmal ist die Ausgabe ein regulärer Vektor von double. UniformOutput wurde standardmäßig auf true .

cellfun ist eine ähnliche Funktion. Der Unterschied zwischen dieser Funktion und arrayfun besteht darin, dass cellfun arbeitet. Wenn Sie nur Namen extrahieren möchten, denen eine Liste mit Dateinamen in einer Zelle 'mydirlist' zugeordnet ist, müssen Sie diese Funktion nur wie folgt ausführen:

mydirnames = cellfun(@(x) x(1:end-4), mydirlist, 'UniformOutput', false)
mydirnames = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

Da es sich bei einer Ausgabe nicht um einen regulären Zahlenvektor handelt, muss eine Ausgabe in einer Zellenvariablen gespeichert werden.

Im folgenden Beispiel füge ich zwei Funktionen in einer zusammen und gebe nur eine Liste von Dateinamen ohne Erweiterung zurück:

cellfun(@(x) x(1:end-4), arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false), 'UniformOutput', false)
ans = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

Es ist verrückt, aber sehr gut möglich, weil arrayfun eine Zelle zurückgibt, deren Eingabe von cellfun erwartet cellfun . Eine UniformOutput dazu ist, dass wir jede dieser Funktionen zwingen können, Ergebnisse in einer UniformOutput , indem Sie UniformOutput explizit auf false setzen. Wir können immer Ergebnisse in einer Zelle erhalten. Wir können möglicherweise keine Ergebnisse in einem regulären Vektor erzielen.

Es gibt eine weitere ähnliche Funktion, die auf Felder einer Struktur structfun : structfun . Ich habe es nicht besonders nützlich gefunden wie die anderen beiden, aber es würde in manchen Situationen glänzen. Wenn Sie beispielsweise wissen möchten, welche Felder numerisch oder nicht numerisch sind, kann der folgende Code die Antwort geben:

structfun(@(x) ischar(x), mydir(1))

Das erste und das zweite Feld einer dir-Struktur sind vom Typ char. Daher ist die Ausgabe:

 1
 1
 0
 0
 0

Die Ausgabe ist auch ein logischer Vektor von true / false . Folglich ist es regelmäßig und kann in einem Vektor gespeichert werden. Es ist nicht notwendig, eine Zellklasse zu verwenden.

Code-Folding-Einstellungen

Es ist möglich, die Code-Folding-Einstellungen an Ihre Bedürfnisse anzupassen. So kann die Code-Faltung für bestimmte Konstrukte aktiviert / deaktiviert werden (z. if block , for loop , Sections ...).

Um Faltvoreinstellungen zu ändern, gehen Sie zu Voreinstellungen -> Code-Faltung:

Geben Sie hier die Bildbeschreibung ein

Dann können Sie auswählen, welcher Teil des Codes gefaltet werden kann.

Einige Informationen:

  • Sie können den gesamten Code in einer Datei auch erweitern oder reduzieren, indem Sie den Cursor an eine beliebige Stelle in der Datei setzen, mit der rechten Maustaste klicken und dann im Kontextmenü Code Folding> Alle einblenden oder Code Folding> Fold All auswählen.
  • Beachten Sie, dass die Faltung dauerhaft ist, in dem Sinne, dass ein Teil des Codes, der erweitert / reduziert wurde, seinen Status behält, nachdem Matlab geschlossen wurde oder die M-Datei geschlossen wurde und wieder geöffnet wird.

Beispiel: So aktivieren Sie das Falten für Abschnitte:

Eine interessante Option ist das Aktivieren von Abschnitten. Abschnitte werden durch zwei Prozentzeichen ( %% ) begrenzt.

Beispiel: Aktivieren Sie das Kontrollkästchen "Abschnitte":

Geben Sie hier die Bildbeschreibung ein

Anstatt einen langen Quellcode zu sehen, ähnlich wie:

Geben Sie hier die Bildbeschreibung ein

Sie können Abschnitte zusammenfalten, um einen allgemeinen Überblick über Ihren Code zu erhalten: Geben Sie hier die Bildbeschreibung ein

Daten extrahieren

Bei einigen Gelegenheiten hatte ich eine interessante Figur, die ich gespeichert habe, aber ich habe den Zugriff auf die Daten verloren. Dieses Beispiel zeigt einen Trick, wie man Informationen aus einer Figur extrahieren kann.

Die wichtigsten Funktionen sind findobj und get . findobj gibt einen Handler für ein Objekt zurück, wenn Attribute oder Eigenschaften des Objekts angegeben werden, z. B. Type oder Color usw. Wenn ein Linienobjekt gefunden wurde , kann get einen beliebigen Wert zurückgeben, der in den Eigenschaften enthalten ist. Es stellt sich heraus, dass die Line Objekte alle Daten in den folgenden Eigenschaften enthalten: XData , YData und ZData ; Die letzte ist normalerweise 0, es sei denn, eine Figur enthält ein 3D-Diagramm.

Mit dem folgenden Code wird eine Beispielabbildung erstellt, die zwei Zeilen, eine Sinusfunktion, einen Schwellenwert und eine Legende zeigt

t = (0:1/10:1-1/10)';
y = sin(2*pi*t);
plot(t,y);
hold on;
plot([0 0.9],[0 0], 'k-');
hold off;
legend({'sin' 'threshold'});

Die erste Verwendung von findobj gibt zwei Handler für beide Zeilen zurück:

findobj(gcf, 'Type', 'Line')
ans = 
  2x1 Line array:

  Line    (threshold)
  Line    (sin)

Um das Ergebnis einzugrenzen, kann findobj auch die Kombination der logischen Operatoren -and , -or und der Eigenschaftsnamen verwenden. Zum Beispiel kann ich ein DiplayName finden, dessen DiplayName sin und dessen XData und YData lesen.

lineh = findobj(gcf, 'Type', 'Line', '-and', 'DisplayName', 'sin');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');

und prüfen, ob die Daten gleich sind.

isequal(t(:),xdata(:))
ans =
     1
isequal(y(:),ydata(:))
ans =
     1

Ebenso kann ich meine Ergebnisse einschränken, indem ich die schwarze Linie (Schwellenwert) ausschließe:

lineh = findobj(gcf, 'Type', 'Line', '-not', 'Color', 'k');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');

und die letzte Prüfung bestätigt, dass die aus dieser Figur extrahierten Daten dieselben sind:

isequal(t(:),xdata(:))
ans =
     1
isequal(y(:),ydata(:))
ans =
     1

Funktionale Programmierung mit anonymen Funktionen

Anonyme Funktionen können zur funktionalen Programmierung verwendet werden. Das Hauptproblem, das gelöst werden muss, ist, dass es keine native Möglichkeit gibt, eine Rekursion zu verankern. Dies kann jedoch immer noch in einer Zeile implementiert werden:

if_ = @(bool, tf) tf{2-bool}();

Diese Funktion akzeptiert einen booleschen Wert und ein Zellenfeld mit zwei Funktionen. Die erste dieser Funktionen wird ausgewertet, wenn der boolesche Wert als wahr ausgewertet wird, und die zweite, wenn der boolesche Wert als falsch ausgewertet wird. Wir können jetzt einfach die Fakultätsfunktion schreiben:

fac = @(n,f) if_(n>1, {@()n*f(n-1,f), @()1});

Das Problem hierbei ist, dass wir einen rekursiven Aufruf nicht direkt aufrufen können, da die Funktion noch keiner Variablen zugeordnet ist, wenn die rechte Seite ausgewertet wird. Wir können diesen Schritt jedoch schriftlich abschließen

factorial_ = @(n)fac(n,fac);

Nun @(n)fac(n,fac) die Funktion der Faktorfunktion rekursiv. Eine andere Möglichkeit, dies bei der funktionalen Programmierung mit einem y-Kombinator zu tun, der auch leicht implementiert werden kann:

y_ = @(f)@(n)f(n,f);

Mit diesem Tool ist die Faktorfunktion noch kürzer:

factorial_ = y_(fac);

Oder direkt:

factorial_ = y_(@(n,f) if_(n>1, {@()n*f(n-1,f), @()1}));

Speichern Sie mehrere Abbildungen in derselben .fig-Datei

Durch das Einfügen mehrerer Zahlengriffe in ein Grafik-Array können mehrere Figuren in derselben .fig-Datei gespeichert werden

h(1) = figure;
scatter(rand(1,100),rand(1,100));

h(2) = figure;
scatter(rand(1,100),rand(1,100));

h(3) = figure;
scatter(rand(1,100),rand(1,100));

savefig(h,'ThreeRandomScatterplots.fig');
close(h);

Dadurch werden 3 Streudiagramme von Zufallsdaten erstellt, wobei jeder Teil des Grafikarrays h ist. Dann kann das Grafikarray wie bei einer normalen Figur mit savefig gespeichert werden, jedoch mit dem Handle des Grafikarrays als zusätzliches Argument.

Eine interessante Randnotiz ist, dass die Figuren in der Regel so angeordnet bleiben, wie sie beim Öffnen gespeichert wurden.

Kommentarblöcke

Wenn Sie einen Teil Ihres Codes kommentieren möchten, können Kommentarblöcke hilfreich sein. Der Kommentarblock beginnt mit einem %{ in einer neuen Zeile und endet mit %} in einer anderen neuen Zeile:

a = 10;
b = 3;
%{
c = a*b;
d = a-b;
%}

Dadurch können Sie die kommentierten Abschnitte falten, um den Code sauberer und kompakter zu gestalten.

Diese Blöcke sind auch nützlich, um Teile Ihres Codes ein- oder auszuschalten. Alles, was Sie tun müssen, um den Block zu kommentieren, ist das Hinzufügen eines weiteren % bevor er angezeigt wird:

a = 10;
b = 3;
%%{ <-- another % over here
c = a*b;
d = a-b;
%}

Manchmal möchten Sie einen Abschnitt des Codes auskommentieren, ohne dessen Einrückung zu beeinflussen:

for k = 1:a
    b = b*k;
    c = c-b;
    d = d*c;
    disp(b)
end

Wenn Sie normalerweise einen Codeblock markieren und die Tastenkombination Strg + r drücken, um ihn auskommentieren zu können (indem automatisch % in alle Zeilen eingefügt wird, und wenn Sie später Strg + i für die automatische Einrückung drücken, wird der Codeblock von der richtigen Hierarchie verschoben Platz und zu viel nach rechts verschoben:

for k = 1:a
    b = b*k;
    %     c = c-b;
    %     d = d*c;
    disp(b)
end

Um dies zu lösen, können Sie Kommentarblöcke verwenden, damit der innere Teil des Blocks richtig eingerückt bleibt:

for k = 1:a
    b = b*k;
    %{
    c = c-b;
    d = d*c;
    %}
    disp(b)
end


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow