Come posso creare tipi enumerati in MATLAB?

Ci sono tipi enumerati in MATLAB? In caso contrario, quali sono le alternative?

Puoi ottenere alcune delle funzionalità con le nuove classi 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 

Questo non è realmente un tipo, ma poiché MATLAB è tipicamente digitato, se si usano numeri interi, si possono fare cose che lo approssimano:

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

In questo caso, le “enum” di MATLAB sono vicine alle enumerazioni in stile C. – syntax sostitutiva per i numeri interi.

Con l’uso attento dei metodi statici, puoi persino fare in modo che le enigmi di MATLAB si avvicinino alla complessità di Ada, ma sfortunatamente con una syntax più maldestra.

A partire da R2010b, MATLAB supporta le enumerazioni.

Esempio dalla documentazione :

 classdef Colors properties R = 0; G = 0; B = 0; end methods function c = Colors(r, g, b) cR = r; cG = g; cB = b; end end enumeration Red (1, 0, 0) Green (0, 1, 0) Blue (0, 0, 1) end end 

Se vuoi fare qualcosa di simile a ciò che Marc ha suggerito, potresti semplicemente creare una struttura per rappresentare i tuoi tipi enumerati invece di una nuova class intera:

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

Un vantaggio è che puoi accedere facilmente alle strutture in due modi diversi. Puoi specificare un campo direttamente usando il nome del campo:

 a = colors.RED; 

oppure puoi usare nomi di campi dinamici se hai il nome del campo in una stringa:

 a = colors.('RED'); 

In realtà, ci sono alcuni vantaggi nel fare ciò che Marc ha suggerito e creare una nuova class per rappresentare un object “enum”:

  • Puoi controllare come l’object viene modificato.
  • È ansible mantenere la definizione in un’unica posizione e utilizzarla facilmente in più punti.
  • È ansible controllare i guasti e renderli più “aggraziati”, come restituire una matrice vuota se si tenta di accedere a un campo inesistente (al contrario di generare un errore).

Tuttavia, se non hai bisogno di quel tipo di complessità e hai solo bisogno di fare qualcosa di veloce, una struttura è probabilmente l’implementazione più semplice e diretta. Funzionerà anche con le versioni precedenti di MATLAB che non utilizzano il più recente framework OOP.

In realtà c’è una parola chiave in MATLAB R2009b chiamata ‘enumerazione’ . Sembra non documentato, e non posso dire di sapere come usarlo, ma probabilmente c’è la funzionalità.

Puoi trovarlo in matlabroot\toolbox\distcomp\examples\+examples

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

È anche ansible utilizzare classi di enumerazione Java dal codice Matlab. Definiscili in Java e inseriscili nel javaclasspath di Matlab.

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

Puoi farli riferimento per nome nel codice 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 

Tuttavia, non prenderà confronti con altri tipi. E il confronto con la stringa ha una dimensione di ritorno dispari.

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

Potresti creare una class Matlab che si comporti come il vecchio pattern enum tipizzato di Java . Una modifica della soluzione di Marc potrebbe portarla da typedef in stile C a qualcosa di simile a enes typesfe in stile Java. In questa versione, i valori nelle costanti sono digitati Oggetti colore.

I lati positivi:

  • Il tipo può essere controllato (in fase di esecuzione) da == e altre operazioni per impedire il confronto casuale con numeri grezzi o altri tipi di enumerazioni.
  • È ansible verificare esplicitamente il tipo delle variabili (in fase di esecuzione).
  • I valori vengono visualizzati con nomi leggibili anziché i codici opachi.
  • Operazioni come mean () e std () che non hanno senso sulle enumerazioni non sono consentite.

Svantaggi:

  • Definizione di class più lunga. Ma questo è tutto il boilerplate e può essere riutilizzato per qualsiasi altra class enum, cambiando solo il nome della class e le proprietà Constant.
  • Queste enumerazioni non possono essere utilizzate direttamente nei blocchi di interruttori. È necessario far uscire il codice, che perde un po ‘di sicurezza.
  • Gli oggetti saranno più lenti dei primitivi. Rilevante se si utilizzano le costanti all’interno dei loop.

Nel complesso, non so quale approccio sia migliore. Non ho usato neanche nella pratica.

 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 

Ecco una funzione per esercitarlo.

 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 

Esempio di utilizzo:

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

Un piccolo inconveniente in entrambi gli approcci: la convenzione C di mettere la costante sulla mano sinistra del “==” per impedire un cattivo incarico non aiuta molto qui. In Matlab, se si utilizza accidentalmente “=” con questa costante sul LHS, invece di un errore, verrà semplicemente creata una nuova variabile di struttura locale denominata Colori e verrà mascherata la class enum.

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

Dopo aver provato gli altri suggerimenti su questa pagina, sono approdato all’approccio totalmente orientato agli oggetti di Andrew. Molto carino – grazie Andrew.

Nel caso in cui qualcuno sia interessato, tuttavia, ho apportato alcuni miglioramenti. In particolare, ho rimosso la necessità di specificare due volte il nome dell’object enum. I nomi sono ora derivati ​​utilizzando il reflection e il sistema metaclass. Inoltre, le funzioni eq () e ismember () sono state riscritte per restituire valori di ritorno opportunamente sagomati per matrici di oggetti enum. Infine, la funzione check_type_safety () è stata modificata per renderla compatibile con le directory dei pacchetti (ad esempio, namespace).

Sembra funzionare bene, ma fammi sapere cosa ne pensi:

 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 

Grazie, Mason

Se hai accesso a Strumenti delle statistiche, potresti prendere in considerazione l’utilizzo di un object categoriale .

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

Se hai bisogno dei tipi enumerati solo per passare all’assembly C # o .NET, puoi build e passare l’enumerazione con MATLAB 2010:

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

puoi anche verificare la risposta ufficiale di MathWorks a

Come utilizzare i valori enumerati .NET in 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, }