How do I create enumerated types in MATLAB?

2019-01-10 18:36发布

Are there enumerated types in MATLAB? If not, what are the alternatives?

10条回答
甜甜的少女心
2楼-- · 2019-01-10 19:05

Starting from R2010b, MATLAB supports enumerations.

Example from the documentation:

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
查看更多
叛逆
3楼-- · 2019-01-10 19:05

After trying out the other suggestions on this page, I landed on Andrew's fully object-oriented approach. Very nice - thanks Andrew.

In case anyone is interested, however, I made (what I think are) some improvements. In particular, I removed the need to double-specify the name of the enum object. The names are now derived using reflection and the metaclass system. Further, the eq() and ismember() functions were re-written to give back properly-shaped return values for matrices of enum objects. And finally, the check_type_safety() function was modified to make it compatible with package directories (e.g. namespaces).

Seems to work nicely, but let me know what you think:

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

Thanks, Mason

查看更多
劫难
4楼-- · 2019-01-10 19:11

You can get some of the functionality with new-style MATLAB classes:

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

This isn't really a type, but since MATLAB is loosely typed, if you use integers, you can do things that approximate it:

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

In this case, MATLAB "enums" are close to C-style enums - substitute syntax for integers.

With the careful use of static methods, you can even make MATLAB enums approach Ada's in sophistication, but unfortunately with clumsier syntax.

查看更多
▲ chillily
5楼-- · 2019-01-10 19:12

If you have access to the Statistics Toolbox, you might consider using a categorical object.

查看更多
老娘就宠你
6楼-- · 2019-01-10 19:13

If you want to do something similar to what Marc suggested, you could simply make a structure to represent your enumerated types instead of a whole new class:

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

One benefit is that you can easily access structures in two different ways. You can specify a field directly using the field name:

a = colors.RED;

or you can use dynamic field names if you have the field name in a string:

a = colors.('RED');

In truth, there are a few benefits to doing what Marc suggested and creating a whole new class to represent an "enum" object:

  • You can control how the object is modified.
  • You can keep the definition in one place and easily use it in multiple places.
  • You can control failures and make them more "graceful", like returning an empty matrix if you try to access a non-existent field (as opposed to throwing an error).

However, if you don't need that sort of complexity and just need to do something quick, a structure is likely the easiest and most straight-forward implementation. It will also work with older versions of MATLAB that don't use the newest OOP framework.

查看更多
我只想做你的唯一
7楼-- · 2019-01-10 19:13

You could also use Java enum classes from your Matlab code. Define them in Java and put them on your Matlab's javaclasspath.

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

You can reference them by name in M-code.

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

It won't catch comparisons to other types, though. And comparison to string has an odd return size.

>> test.ColorEnum.RED == 'GREEN'
ans =
     0
>> test.ColorEnum.RED == 'RED'
ans =
     1     1     1
查看更多
登录 后发表回答