matlab enums matlab-class

¿Cómo creo tipos enumerados en MATLAB?



enums matlab-class (10)

¿Hay tipos enumerados en MATLAB? si no, cuales son las alternativas?


A partir de R2010b, MATLAB admite enumeraciones.

Ejemplo de la 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


Después de probar las otras sugerencias en esta página, llegué al enfoque totalmente orientado a objetos de Andrew. Muy bien, gracias Andrew.

En caso de que alguien esté interesado, sin embargo, hice (lo que creo que son) algunas mejoras. En particular, eliminé la necesidad de especificar dos veces el nombre del objeto enum. Los nombres ahora se derivan usando la reflexión y el sistema de metaclase. Además, las funciones eq () y ismember () se volvieron a escribir para devolver valores de retorno con la forma adecuada para matrices de objetos enum. Y finalmente, se modificó la función check_type_safety () para que sea compatible con los directorios de paquetes (por ejemplo, espacios de nombres).

Parece que funciona bien, pero déjame saber lo que piensas:

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

Gracias, Mason


En realidad, hay una palabra clave en MATLAB R2009b llamada ''enumeración'' . Parece que no está documentado, y no puedo decir que sé cómo usarlo, pero la funcionalidad probablemente esté allí.

Puede encontrarlo en matlabroot/toolbox/distcomp/examples/+examples

classdef(Enumeration) DmatFileMode < int32 enumeration ReadMode(0) ReadCompatibilityMode(1) WriteMode(2) end <snip> end


Podrías crear una clase de Matlab que se comporte como un antiguo modelo de enumeración seguro de Java . Una modificación de la solución de Marc podría llevarlo desde los typedefs tipo C a más como enum de tipo tipo Java. En esta versión, los valores en las constantes son objetos de Color tipeados.

Las ventajas:

  • El tipo puede ser verificado (en tiempo de ejecución) por == y otras operaciones para evitar la comparación accidental con los valores numéricos en bruto u otros tipos de enumeraciones.
  • Puede verificar explícitamente el tipo de sus variables (en tiempo de ejecución).
  • Los valores se muestran con nombres legibles en lugar de los códigos opacos.
  • Las operaciones como mean () y std () que no tienen sentido en las enumeraciones no están permitidas.

Desventajas:

  • Definición de clase más larga. Pero, esto es todo repetitivo, y puede reutilizarse para cualquier otra clase enum, cambiando solo el nombre de la clase y las propiedades de Constante.
  • Estas enumeraciones no se pueden usar directamente en bloques de interruptores. Necesitas sacar el código, lo que pierde algún tipo de seguridad.
  • Los objetos serán más lentos que los primitivos. Pertinente si está usando constantes dentro de los bucles.

En general, no sé qué enfoque es mejor. No lo he usado en la práctica.

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

Aquí hay una función para ejercitarlo.

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

Ejemplo de uso:

>> 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 >>

Una peculiaridad menor en ambos enfoques: la convención C de poner la constante en la mano izquierda del "==" para evitar una mala asignación no ayuda mucho aquí. En Matlab, si accidentalmente usas "=" con esta constante en el LHS, en lugar de un error, creará una nueva variable de estructura local llamada Colors, y enmascarará la clase enum.

>> Colors.BLUE = 42 Colors = BLUE: 42 >> Color.BLUE = 42 Color = BLUE: 42 >> Color.RED ??? Reference to non-existent field ''RED''.


Puede obtener algunas de las funcionalidades con las nuevas clases de 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

Esto no es realmente un tipo, pero como MATLAB está tipeado libremente, si usas números enteros, puedes hacer cosas que se aproximen a él:

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

En este caso, las "enumeraciones" de MATLAB están cerca de enums de estilo C: sintaxis sustituta para enteros.

Con el uso cuidadoso de métodos estáticos, incluso puede hacer que las enumeraciones de MATLAB se acerquen a la sofisticación de Ada, pero desafortunadamente con una sintaxis más torpe.


Si desea hacer algo similar a lo sugerido por Marc , simplemente podría hacer una structure para representar sus tipos enumerados en lugar de una clase completamente nueva:

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

Un beneficio es que puede acceder fácilmente a las estructuras de dos maneras diferentes. Puede especificar un campo directamente usando el nombre del campo:

a = colors.RED;

o puede usar nombres de campo dinámicos si tiene el nombre del campo en una cadena:

a = colors.(''RED'');

En verdad, hay algunos beneficios de hacer lo que Marc sugirió y crear una clase completamente nueva para representar un objeto "enum":

  • Puedes controlar cómo se modifica el objeto.
  • Puede mantener la definición en un solo lugar y usarla fácilmente en múltiples lugares.
  • Puede controlar las fallas y hacerlas más "elegantes", como devolver una matriz vacía si intenta acceder a un campo inexistente (en lugar de arrojar un error).

Sin embargo, si no necesita ese tipo de complejidad y solo necesita hacer algo rápido, una estructura es probablemente la implementación más sencilla y directa. También funcionará con versiones anteriores de MATLAB que no usan el marco de OOP más nuevo.


Si necesita los tipos enumerados solo para pasar al ensamblado C # o .NET, puede construir y pasar las enumeraciones con MATLAB 2010:

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

también puede verificar la respuesta oficial de MathWorks en

¿Cómo uso los valores enumerados de .NET en MATLAB 7.8 (R2009a)?

// the enum "MyAlerts" in c# will look something like this public enum MyAlerts { value_1 = 0, value_2 = 1, MyAlerts_Count = 2, }


Si tiene acceso a Statistics Toolbox, puede considerar el uso de un objeto categórico .


También puede usar las clases enum de Java desde su código Matlab. Defínelos en Java y colóquelos en el javaclasspath de Matlab.

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

Puede hacer referencia a ellos por su nombre en 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

Sin embargo, no tomará comparaciones con otros tipos. Y la comparación con la cadena tiene un tamaño de retorno impar.

>> test.ColorEnum.RED == ''GREEN'' ans = 0 >> test.ColorEnum.RED == ''RED'' ans = 1 1 1


Toys = {''Buzz'', ''Woody'', ''Rex'', ''Hamm''}; Toys{3} ans = ''Rex''