44

MATLAB に列挙型はありますか? そうでない場合、代替手段は何ですか?

4

10 に答える 10

44

R2010b以降、MATLABは列挙をサポートしています。

ドキュメントからの例:

classdef Colors
   properties
      R = 0;
      G = 0;
      B = 0;
   end

   methods
      function c = Colors(r, g, b)
         c.R = r; c.G = g; c.B = b;
      end
   end

   enumeration
      Red   (1, 0, 0)
      Green (0, 1, 0)
      Blue  (0, 0, 1)
   end
end
于 2010-11-06T02:58:38.823 に答える
27

新しいスタイルの MATLAB クラスを使用して、いくつかの機能を取得できます。

classdef (Sealed) Colors
    properties (Constant)
        RED = 1;
        GREEN = 2;
        BLUE = 3;
    end

    methods (Access = private)    % private so that you cant instantiate
        function out = Colors
        end
    end
end

これは実際には型ではありませんが、MATLAB は緩やかに型付けされているため、整数を使用すると、それに近似することができます。

line1 = Colors.RED;
...
if Colors.BLUE == line1
end

この場合、MATLAB の「列挙型」は C スタイルの列挙型 (整数の代替構文) に近いものです。

静的メソッドを慎重に使用することで、MATLAB 列挙型を Ada の列挙型に近づけることもできますが、残念なことに構文が扱いにくくなります。

于 2009-09-07T22:58:03.610 に答える
18

Marcが提案したのと同様のことをしたい場合は、まったく新しいクラスではなく、列挙型を表す構造を作成するだけで済みます。

colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);

1つの利点は、2つの異なる方法で構造に簡単にアクセスできることです。フィールド名を使用して、フィールドを直接指定できます。

a = colors.RED;

または、文字列にフィールド名がある場合は、動的フィールド名を使用できます。

a = colors.('RED');

実際、Marcが提案したことを実行し、「列挙型」オブジェクトを表すまったく新しいクラスを作成することには、いくつかの利点があります。

  • オブジェクトの変更方法を制御できます。
  • 定義を1つの場所に保持して、複数の場所で簡単に使用できます。
  • (エラーをスローするのではなく)存在しないフィールドにアクセスしようとした場合に空のマトリックスを返すなど、障害を制御してより「適切」にすることができます。

ただし、そのような複雑さを必要とせず、何かをすばやく実行する必要がある場合は、構造が最も簡単で最も簡単な実装である可能性があります。また、最新のOOPフレームワークを使用しない古いバージョンのMATLABでも機能します。

于 2009-09-08T15:31:24.133 に答える
8

実際には、MATLABR2009bには「列挙型」というキーワードがあります。文書化されていないようで、使い方がわからないとは言えませんが、機能はそこにあると思います。

あなたはそれを見つけることができますmatlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32

    enumeration
        ReadMode(0)
        ReadCompatibilityMode(1)
        WriteMode(2)
    end
<snip>
end
于 2009-10-31T08:56:57.877 に答える
7

Matlab コードから Java enum クラスを使用することもできます。それらを Java で定義し、Matlab の javaclasspath に配置します。

// Java class definition
package test;
public enum ColorEnum {
    RED, GREEN, BLUE
}

M コードで名前で参照できます。

mycolor = test.ColorEnum.RED
if mycolor == test.ColorEnum.RED
    disp('got red');
else
    disp('got other color');
end

% Use ordinal() to get a primitive you can use in a switch statement
switch mycolor.ordinal
    case test.ColorEnum.BLUE.ordinal
        disp('blue');
    otherwise
        disp(sprintf('other color: %s', char(mycolor.toString())))
end

ただし、他のタイプとの比較はキャッチされません。また、文字列と比較すると、戻り値のサイズが奇妙になります。

>> test.ColorEnum.RED == 'GREEN'
ans =
     0
>> test.ColorEnum.RED == 'RED'
ans =
     1     1     1
于 2009-09-09T21:49:45.883 に答える
5

Java の古い typesafe enum pattern のように動作する Matlab クラスを作成できます。Marc のソリューションを変更すると、C スタイルの typedef から、Java スタイルのタイプセーフな列挙型に似たものになる可能性があります。このバージョンでは、定数の値は型指定された Color オブジェクトです。

利点:

  • 型は、== およびその他の操作によって (実行時に) チェックすることができ、生の数値または他の型の列挙型との偶発的な比較を防ぎます。
  • 変数の型を (実行時に) 明示的に確認できます。
  • 値は、不透明なコードではなく、読み取り可能な名前で表示されます。
  • 列挙型では意味をなさない mean() や std() などの操作は許可されていません。

欠点:

  • より長いクラス定義。ただし、これはすべてボイラープレートであり、クラス名と定数プロパティだけを変更して、他の列挙型クラスに再利用できます。
  • これらの列挙型は、switch ブロックで直接使用できません。コードをポップアウトする必要があるため、型の安全性が失われます。
  • オブジェクトはプリミティブよりも遅くなります。ループ内で定数を使用している場合に関連します。

全体として、どのアプローチが優れているかはわかりません。どちらも実際には使用していません。

classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab

properties (Constant)
    RED = Color(1, 'RED');
    GREEN = Color(2, 'GREEN');
    BLUE = Color(3, 'BLUE');
end
properties (SetAccess=private)
    % All these properties are immutable.
    Code;
    Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods (Access = private)
%private so that you can't instatiate directly
    function out = Color(InCode, InName)
        out.Code = InCode;
        out.Name = InName;
    end       
end
methods (Static = true)
    function needa(obj)
    %NEEDA Asserts that obj must be a Color
        if ~isa(obj, mfilename)
            error('Input must be a %s; got a %s', mfilename, class(obj));
        end
    end
end
methods (Access = public)
    function display(obj)
      disp([inputname(1) ' =']);
      disp(obj);
    end
    function disp(obj)
        if isscalar(obj)
            disp(sprintf('%s: %s (%d)', class(obj), obj.Name, obj.Code));
        else
            disp(sprintf('%s array: size %s', class(obj), mat2str(size(obj))));
        end
    end    
    function out = eq(a, b)
        %EQ Basic "type-safe" eq
        check_type_safety(a, b);
        out = [a.Code] == [b.Code];
    end
    function [tf,loc] = ismember(a, b)
        check_type_safety(a, b);
        [tf,loc] = ismember([a.Code], [b.Code]);
    end
    function check_type_safety(varargin)
        %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
        for i = 1:nargin
            if ~isa(varargin{i}, mfilename)
                error('Non-typesafe comparison of %s vs. %s', mfilename, class(varargin{i}));
            end
        end
    end
end
end

これを実行する関数があります。

function do_stuff_with_color(c)
%DO_STUFF_WITH_COLOR Demo use of the Color typesafe enum

Color.needa(c); % Make sure input was a color
if (c == Color.BLUE)
    disp('color was blue');
else
    disp('color was not blue');
end

% To work with switch statements, you have to explicitly pop the code out 
switch c.Code
    case Color.BLUE.Code
        disp('blue');
    otherwise
        disp(sprintf('some other color: %s', c.Name));
end

使用例:

>> Color.RED == Color.RED
ans =
     1
>> Color.RED == 1
??? Error using ==> Color>Color.check_type_safety at 55
Non-typesafe comparison of Color vs. double

Error in ==> Color>Color.eq at 44
        check_type_safety(a, b);

>> do_stuff_with_color(Color.BLUE)
color was blue
blue
>> do_stuff_with_color(Color.GREEN)
color was not blue
some other color: GREEN
>> do_stuff_with_color(1+1) % oops - passing the wrong type, should error
??? Error using ==> Color>Color.needa at 26
Input must be a Color; got a double

Error in ==> do_stuff_with_color at 4
Color.needa(c); % Make sure input was a color

>> 

両方のアプローチのちょっとした癖: 「==」の左側に定数を置いて不適切な代入を防ぐという C の規則は、ここではあまり役に立ちません。Matlab では、LHS でこの定数に誤って "=" を使用すると、エラーではなく、Colors という名前の新しいローカル構造体変数が作成され、enum クラスがマスクされます。

>> Colors.BLUE = 42
Colors = 
    BLUE: 42
>> Color.BLUE = 42
Color = 
    BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
于 2009-09-09T21:26:20.650 に答える
4

Statistics Toolbox にアクセスできる場合は、カテゴリ オブジェクトの使用を検討してください。

于 2009-09-09T20:46:38.690 に答える
3

このページの他の提案を試した後、Andrew の完全なオブジェクト指向アプローチにたどり着きました。とても素敵です - アンドリューに感謝します。

ただし、誰かが興味を持っている場合に備えて、いくつかの改善を行いました(私が思うに)。特に、enum オブジェクトの名前を二重に指定する必要がなくなりました。名前は、リフレクションとメタクラス システムを使用して派生するようになりました。さらに、 eq() および ismember() 関数が書き直され、enum オブジェクトの行列に対して適切な形状の戻り値が返されました。そして最後に、check_type_safety() 関数が変更され、パッケージ ディレクトリ (名前空間など) と互換性を持つようになりました。

うまく機能しているように見えますが、あなたの考えを教えてください:

classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab

properties (Constant)
    RED = Color(1);
    GREEN = Color(2);
    BLUE = Color(3);
end
methods (Access = private) % private so that you can''t instatiate directly
    function out = Color(InCode)
        out.Code = InCode;
    end       
end


% ============================================================================
% Everything from here down is completely boilerplate - no need to change anything.
% ============================================================================
properties (SetAccess=private) % All these properties are immutable.
    Code;
end
properties (Dependent, SetAccess=private)
    Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods
    function out = eq(a, b) %EQ Basic "type-safe" eq
        check_type_safety(a, b);
        out = reshape([a.Code],size(a)) == reshape([b.Code],size(b));
    end
    function [tf,loc] = ismember(a, b)
        check_type_safety(a, b);
        [tf,loc] = ismember(reshape([a.Code],size(a)), [b.Code]);
    end
    function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
        theClass = class(varargin{1});
        for ii = 2:nargin
            if ~isa(varargin{ii}, theClass)
                error('Non-typesafe comparison of %s vs. %s', theClass, class(varargin{ii}));
            end
        end
    end

    % Display stuff:
    function display(obj)
        disp([inputname(1) ' =']);
        disp(obj);
    end
    function disp(obj)
        if isscalar(obj)
            fprintf('%s: %s (%d)\n', class(obj), obj.Name, obj.Code);
        else
            fprintf('%s array: size %s\n', class(obj), mat2str(size(obj)));
        end
    end    
    function name=get.Name(obj)
        mc=metaclass(obj);
        mp=mc.Properties;
        for ii=1:length(mp)
            if (mp{ii}.Constant && isequal(obj.(mp{ii}.Name).Code,obj.Code))
                name = mp{ii}.Name;
                return;
            end;
        end;
        error('Unable to find a %s value of %d',class(obj),obj.Code);
    end;
end
end

ありがとう、メイソン

于 2010-07-13T17:56:10.380 に答える
2
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'};

Toys{3}
  ans = 'Rex'
于 2013-04-01T20:21:52.610 に答える
1

C# または .NET アセンブリに渡すためだけに列挙型が必要な場合は、MATLAB 2010 で列挙型を作成して渡すことができます。

A = NET.addAssembly(MyName.dll)
% suppose you have enum called "MyAlerts" in your assembly
myvar = MyName.MyAlerts.('value_1');

また、公式の MathWorks の回答を確認することもできます。

MATLAB 7.8 (R2009a) で .NET 列挙値を使用するにはどうすればよいですか?

// the enum "MyAlerts" in c# will look something like this
public enum MyAlerts
{
    value_1 = 0,
    value_2 = 1,
    MyAlerts_Count = 2,
}
于 2011-03-16T15:27:42.293 に答える