MATLAB Language
役に立つトリック
サーチ…
セルと配列で動作する便利な関数
この簡単な例では、MATLAB: cellfun
、 arrayfun
使用を開始して以来、非常に便利な機能について説明しています。アイデアは、配列またはセルクラスの変数をとり、すべての要素をループし、各要素に専用の関数を適用することです。適用される関数は、通常は匿名でも、* .mファイルで定義された正規関数でもかまいません。
簡単な問題から始めて、フォルダに与えられた* .matファイルのリストを見つける必要があるとしましょう。この例では、まず、現在のフォルダに* .matファイルをいくつか作成しましょう:
for n=1:10; save(sprintf('mymatfile%d.mat',n)); end
コードを実行した後、拡張子が* .matの10個の新しいファイルが存在するはずです。すべての* .matファイルを一覧表示するコマンドを実行すると、次のようになります。
mydir = dir('*.mat');
我々は、dir構造の要素の配列を取得する必要があります。 MATLABはこれと同様の出力を与える必要があります:
10x1 struct array with fields:
name
date
bytes
isdir
datenum
ご覧のとおり、この配列の各要素は、いくつかのフィールドを持つ構造体です。すべての情報は実際には各ファイルに関して重要ですが、99%ではファイル名に関心があり、それ以外は何もありません。構造体配列から情報を抽出するために、正しいサイズの一時変数を作成し、ループで各要素の名前を抽出し、作成した変数に保存するローカル関数を作成しました。同じ結果を達成するためのより簡単な方法は、前述の関数の1つを使用することです。
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'
この機能はどのように機能しますか?これは通常、2つのパラメータをとります:最初のパラメータとしての関数ハンドルと配列。関数は与えられた配列の各要素に対して作用します。 3番目と4番目のパラメータはオプションですが重要です。出力が規則的でないことがわかったら、セルに保存する必要があります。これは、 UniformOutput
false
を設定することを指摘する必要があります。デフォルトでは、この関数は数字のベクトルなどの通常の出力を返します。例えば、各ファイルがどれくらいのディスクスペースをバイト単位で取得したかに関する情報を抽出しましょう。
mydirbytes = arrayfun(@(x) x.bytes, dir('*.mat'))
mydirbytes =
34560
34560
34560
34560
34560
34560
34560
34560
34560
34560
キロバイト:
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
今回は、出力はdoubleの規則的なベクトルになります。 UniformOutput
はデフォルトでtrue
に設定されていました。
cellfun
も同様の機能です。この関数とarrayfun
の違いは、 cellfun
がセルクラス変数で動作することです。セル 'mydirlist'にファイル名のリストがある名前だけを抽出したい場合は、次のようにこの関数を実行するだけです:
mydirnames = cellfun(@(x) x(1:end-4), mydirlist, 'UniformOutput', false)
mydirnames =
'mymatfile1'
'mymatfile10'
'mymatfile2'
'mymatfile3'
'mymatfile4'
'mymatfile5'
'mymatfile6'
'mymatfile7'
'mymatfile8'
'mymatfile9'
ここでも、出力は数値の正規のベクトルではないため、出力はセル変数に保存する必要があります。
以下の例では、2つの関数を1つにまとめ、拡張子のないファイル名のリストのみを返します。
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'
arrayfun
はcellfun
予想される入力であるセルを返すので、これは夢中ですが非常に可能です。これには、 UniformOutput
を明示的にfalseに設定することによって、これらの関数のいずれかに結果をセル変数に返すよう強制することができます。私たちは常に細胞内で結果を得ることができます。我々は、結果を通常のベクトルで得ることができないかもしれない。
構造体: structfun
フィールドで操作するもう1つの類似した関数があります。私は他の2人と同じくらい役に立つとは思えませんでしたが、いくつかの状況では輝くでしょう。たとえば、どのフィールドが数値か非数値かを知りたい場合、次のコードで答えを得ることができます:
structfun(@(x) ischar(x), mydir(1))
dir構造体の最初と2番目のフィールドはchar型です。したがって、出力は次のようになります。
1
1
0
0
0
また、出力はtrue
/ false
論理ベクトルです。従って、それは規則的であり、ベクターに保存することができる。セルクラスを使用する必要はありません。
コード折りたたみ設定
必要に応じてコード折りたみの設定を変更することができます。したがって、コードの折りたたみを特定の構造体(例: if block
、 for loop
、 Sections
...)に対して有効/無効に設定できます。
折りたたみ設定を変更するには、環境設定 - >コード折りたたみ:
コードのどの部分を折り畳むかを選択できます。
いくつかの情報:
- ファイル内の任意の場所にカーソルを置き、右クリックしてコンテキストメニューから[コード折りたたみ]> [すべて展開]または[コード折りたたみ]> [すべて折りたたむ]を選択して、ファイル内のすべてのコードを展開または折りたたむこともできます。
- 折りたたみは永続的です。つまり、展開/折りたたまれたコードの一部は、Matlabまたはmファイルが閉じられて再オープンされた後でも状態を保持します。
例:セクションの折り畳みを有効にするには:
興味深いオプションは、セクションを折り畳むことを可能にすることです。セクションは2つのパーセント記号(
%%
)で区切られています。例:「セクション」チェックボックスをオンにするには:
次に、次のような長いソースコードを見るのではなく、
図データの抽出
私はいくつかの機会に私が保存した面白い人物を持っていましたが、私はそのデータへのアクセスを失いました。この例は、Figureから情報を抽出する方法を示すトリックです。
主要な機能はfindobjとgetです。 findobjは、オブジェクトの属性またはプロパティ( Type
やColor
など)を指定されたオブジェクトにハンドラを返します。行オブジェクトが見つかると、 getはプロパティによって保持されている値を返します。 Line
オブジェクトは、 XData
、 YData
、 ZData
プロパティのすべてのデータを保持しています。 Figureに3Dプロットが含まれていない限り、最後のものは通常0です。
次のコードは、sin関数としきい値と凡例の2つの行を示す図の例を作成します
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'});
findobjを最初に使用すると、2つのハンドラが両方の行に返されます。
findobj(gcf, 'Type', 'Line')
ans =
2x1 Line array:
Line (threshold)
Line (sin)
結果を絞り込むために、 findobjは論理演算子-and
、 -or
プロパティ名の組み合わせも使用できます。たとえば、私はDiplayName
がsin
である行オブジェクトを見つけて、そのXData
とYData
を読み取ることができます。
lineh = findobj(gcf, 'Type', 'Line', '-and', 'DisplayName', 'sin');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');
データが等しいかどうかを確認します。
isequal(t(:),xdata(:))
ans =
1
isequal(y(:),ydata(:))
ans =
1
同様に、私は黒線(閾値)を除外して結果を絞り込むことができます:
lineh = findobj(gcf, 'Type', 'Line', '-not', 'Color', 'k');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');
最後のチェックでは、この図から抽出されたデータが同じであることが確認されます。
isequal(t(:),xdata(:))
ans =
1
isequal(y(:),ydata(:))
ans =
1
匿名関数を使用した関数型プログラミング
匿名関数は、関数型プログラミングに使用できます。解決しなければならない主な問題は、再帰をアンカーするためのネイティブな方法がないということですが、これは引き続き1行で実装できます。
if_ = @(bool, tf) tf{2-bool}();
この関数は、ブール値と2つの関数のセル配列を受け入れます。ブール値がtrueと評価された場合、最初の関数が評価され、ブール値がfalseと評価された場合は2番目の関数が評価されます。階乗関数を簡単に書くことができます:
fac = @(n,f) if_(n>1, {@()n*f(n-1,f), @()1});
ここでの問題は、右辺が評価されたときに関数が変数に割り当てられていないため、再帰呼び出しを直接呼び出すことができないことです。しかし、私たちはこの手順を書いて完了することができます
factorial_ = @(n)fac(n,fac);
今、 @(n)fac(n,fac)
は、階乗関数を再帰的にevaulatesする。簡単に実装できるy-コンビネータを使用した関数型プログラミングでこれを行う別の方法:
y_ = @(f)@(n)f(n,f);
このツールでは、階乗関数はさらに短くなります。
factorial_ = y_(fac);
または直接:
factorial_ = y_(@(n,f) if_(n>1, {@()n*f(n-1,f), @()1}));
複数の図を同じ.figファイルに保存する
複数のFigureハンドルをグラフィックス配列に配置することにより、複数のFigureを同じ.figファイルに保存することができます
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);
これにより、ランダムなデータの3つの散布図が作成され、グラフィック配列hの各部分が作成されます。グラフィックス配列は通常の図形のようにsavefigを使用して保存することができますが、グラフィックス配列のハンドルは追加の引数として使用できます。
面白いのは、数字を開くときに保存されたのと同じ方法で配置されている傾向があるということです。
コメントブロック
あなたのコードの一部をコメントしたいなら、コメントブロックが役に立つかもしれません。コメントブロックは、新しい行に%{
で始まり、 %}
で終わります。
a = 10;
b = 3;
%{
c = a*b;
d = a-b;
%}
これにより、コードをよりクリーンでコンパクトにするために、コメントしたセクションを折り畳むことができます。
これらのブロックは、コードのオン/オフの切り替えにも役立ちます。ブロックのコメントを外すために必要な作業は、それが始まる前に別の%
追加することです。
a = 10;
b = 3;
%%{ <-- another % over here
c = a*b;
d = a-b;
%}
場合によっては、コードの一部をコメントアウトしたいが、インデントには影響を与えない。
for k = 1:a
b = b*k;
c = c-b;
d = d*c;
disp(b)
end
通常、コードブロックをマークしてCtrl + rを押してコメントアウトすると( %
自動的にすべての行に追加すると、後でCtrl + iを押すと自動インデントされます)、コードブロックは正しい階層から移動します右に移動しすぎると、
for k = 1:a
b = b*k;
% c = c-b;
% d = d*c;
disp(b)
end
これを解決する方法は、コメントブロックを使用することです。そのため、ブロックの内部は正しくインデントされたままです。
for k = 1:a
b = b*k;
%{
c = c-b;
d = d*c;
%}
disp(b)
end