Help us understand the problem. What is going on with this article?

世界一短いMATLAB関数(自称)を書いた

「~をする関数を最小何行で書けるか」というチャレンジ、よくプログラミングコンテストで聞きますよね。

この記事では私がMATLABのある機能を勉強していた時にたまたま書いた「世界一短い関数」について書きます。「世界一」と言うと物言いがつきそうですが、飽くまで自称ということで...

関数の振る舞い

まずは何をする関数かみてみましょう。

>> data = {123, [1 2 3], 'xyz'};
>> [a,b,c] = my_fun(data)
a =
   123
b =
     1     2     3
c =
    'xyz'

これはセル配列を入力として受け、要素をそれぞれの出力変数に割り当てる関数です。

通常、これをMATLABでやろうとするとこんな感じになります。

>> a = data{1}
a =
   123
>> b = data{2}
b =
     1     2     3
>> c = data{3}
c =
    'xyz'

ということで、まず今回作った関数がそれなりの使い道があるものという事で話を進めます。

関数定義

では、この関数の中身を見てみましょう。
.
.
.
.
.
.
.
.
.
.
.
.
ハラハラ
.
.
.
.
.
.
.
.
.
.
.
.
.
ドキドキ
.
.
.
.
.
.
.
.
.
.
.
ジャジャン!
.
.
.
.
.

my_fun.m
function varargout = my_fun(varargout)

以上です。

「世界一短い関数」と聞いて無名関数を想像した方もいるかもしれませんが、これは実際の関数ファイルです。1行の関数ファイル、しかも必要最小限の要素からなっています。

  • 関数宣言のキーワード:function
  • 出力引数:varargout
  • 関数名:my_fun
  • 入力引数:varargout

一見、ただ入力をそのまま出力に流しているように見える関数ですが、実はそこにはMATLAB特有の性質が生かされているのです。

解説

ポイントは変数varargoutです。これは実は普通の変数と違って、出力引数に使われた時に特別な役割を果たすのです。ドキュメンテーションを見てみましょう。

varargout は、任意の数の出力引数を関数で返すことを可能にする関数定義ステートメントの出力変数です。小文字を使用して varargout を指定し、明示的に宣言された出力の後に最後の出力引数として含めます。関数を実行した場合、varargout は 1 行 N 列の cell 配列となり、N は明示的に宣言された出力の後に要求された出力の数を表します。

う~ん。どういう事でしょう。

まず、MATLABの性質として言えるのが、MATLABは柔軟性をもった呼び出し構文に対応しているという事。つまり、関数の書き方によっては異なる引数(数や型)に対応します。例えば、size関数を見てみましょう。

>> x = [1 2;3 4;5 6];
>> sz = size(x) % 変数のサイズをベクトルとして返す
sz =
     3     2
>> [m,n] = size(x) % 第1と第2次元のサイズを個々の変数に返す
m =
     3
n =
     2
>> n = size(x,2) % 第2次元のサイズを返す
n =
     2

このような、柔軟性をもった関数を書くときに便利なのがvararginvarargoutです。

本来はvararginは任意の数の入力引数を受け付けるときに使い、varargoutは任意の数の出力引数を返すときに使いますが、今回は入力と出力両方にvarargoutを使うのがポイントです。ここで、もう一度ドキュメンテーションの文章を読み返してみましょう。

関数を実行した場合、varargout は 1 行 N 列の cell 配列となり...

そう。つまり変数varargoutはもともとセル配列という扱いなのです。また、そのセル配列の各要素は関数を呼ぶときに指定した出力引数に順次割り当てられるのです。例えば、もし関数の中でvarargout{123, [1 2 3], 'abc'}というセル配列であったとすると、その関数を

>> [a,b,c] = my_fun(...)

と呼んだとしたらセルの要素がそれぞれabcに代入されるのです。

今回のmy_funでは入力引数にも同じ名前のvarargoutを使ったので(しかも入力引数のvarargoutは普通の変数扱い)、外から入力されたデータがそのままvarargoutに代入されます。今回の例のように外からセル配列が渡されると、本来varargoutが期待しているものとなるのでうまくいくのです。

まとめてみますと、

  1. セル配列dataを関数入力として渡す
  2. 関数内ではセル配列データが変数varargoutに代入される
  3. セル配列データvarargoutが任意の数の出力引数として返される
  4. セル配列の要素が用意された出力変数abcに代入される

補足

今回は計算など一切しない、MATLABの性質を生かした簡単な関数を作成しましたが、本来ですとちゃんとエラーチェックなどをして、入力が期待する型やサイズなのかをチェックするのがベストプラクティスだと思います。ただ、「世界最小」にこだわりたかっただけです。。。

varargoutでできるという事は、vararginでもできます。

my_fun2.m
function varargin = my_fun2(varargin)

解説は省きますが、この関数は任意の数の入力を一つのセル配列にまとめてくれます。

>> a = 123;
>> b = [1 2 3];
>> c = 'xyz';
>> data2 = my_fun2(a,b,c)
data2 =
  1×3  cell 配列
    {[123]}    {1×3 double}    {'xyz'}

ただ、これはもっと分かり易い推奨する方法があるので関数にするメリットはありませんね。

>> data2 = {a,b,c}
data2 =
  1×3  cell 配列
    {[123]}    {1×3 double}    {'xyz'}

MATLABプログラミング

私は殆ど他のプログラミング言語の経験はないので(BASIC、Pascal、Javaは多少あり)、MATLABバカといわれてもしょうがないかと思いますが、私がMATLABで一番気に入っているのはプログラミングの部分です。最近はToolboxがかなり充実してきていますが、やはりMATLAB言語の部分にいつも惹かれます。ということで、R2019bで私が一番気に入っている機能を紹介してこの記事は終わりにさせて頂きます。

Function Argument Validation

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした