Comment créer des types énumérés dans MATLAB?

y a-t-il des types énumérés dans MATLAB? Dans la négative, quelles sont les solutions de rechange?

41
demandé sur chappjc 2009-09-07 15:58:00

10 réponses

vous pouvez obtenir une partie de la fonctionnalité avec des classes MATLAB nouveau style:

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

ce n'est pas vraiment un type, mais puisque MATLAB est vaguement tapé, si vous utilisez des nombres entiers, vous pouvez faire des choses qui s'en rapprochent:

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

dans ce cas, MATLAB" enums " sont proches de C-style enums - syntaxe de substitution pour les entiers.

avec l'utilisation prudente de méthodes statiques, vous pouvez même faire MATLAB enums approche Ada dans sophistication, mais malheureusement avec une syntaxe plus maladroite.

23
répondu Marc 2012-11-20 15:30:44

à partir de R2010b, MATLAB supporte les énumérations.

exemple tiré 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
40
répondu Jonas 2012-11-20 15:25:10

si vous voulez faire quelque chose similaire à ce que Marc suggéré, vous pouvez simplement faire une structure pour représenter vos types énumérés au lieu d'une toute nouvelle classe:

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

un avantage est que vous pouvez facilement accéder aux structures de deux façons différentes. Vous pouvez spécifier un champ directement en utilisant le nom du champ:

a = colors.RED;

ou vous pouvez utiliser noms des champs dynamiques si vous avez le nom du champ dans une chaîne de caractères:

a = colors.('RED');

en vérité, il y a quelques avantages à faire ce que Marc a suggéré et à créer une toute nouvelle classe pour représenter un" enum "objet:

  • vous pouvez contrôler comment l'objet est modifié.
  • vous pouvez conserver la définition à un seul endroit et l'utiliser facilement à plusieurs endroits.
  • vous pouvez contrôler les pannes et faire plus "gracieux", comme au retour d'une matrice vide si vous essayez d'accéder à un champ inexistant (par opposition à lancer une erreur).

cependant, si vous n'avez pas besoin de ce genre de complexité et juste besoin de faire quelque chose rapidement, une structure est probablement l'implémentation la plus facile et la plus simple. Il fonctionnera également avec les versions plus anciennes de MATLAB qui n'utilisent pas le nouveau cadre OOP.

15
répondu gnovice 2018-09-21 03:26:39

il y a en fait un mot-clé dans MATLAB R2009b appelé " enumeration " . Il semble être sans-papiers, et je ne peux pas dire que je sais comment l'utiliser, mais la fonctionnalité est probablement là.

vous pouvez le trouver dans matlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32

    enumeration
        ReadMode(0)
        ReadCompatibilityMode(1)
        WriteMode(2)
    end
<snip>
end
8
répondu kv. 2012-11-20 15:22:54

vous pouvez également utiliser les classes Java enum à partir de votre code Matlab. Définissez-les en Java et mettez-les sur le javaclasspath de votre Matlab.

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

vous pouvez les référencer par leur nom 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

il ne sera pas des comparaisons avec d'autres types, cependant. Et la comparaison à la chaîne a une taille de retour Impair.

>> test.ColorEnum.RED == 'GREEN'
ans =
     0
>> test.ColorEnum.RED == 'RED'
ans =
     1     1     1
7
répondu Andrew Janke 2009-09-09 21:49:45

vous pouvez faire une classe de Matlab qui se comporte comme un Java ancienne Typesafe enum pattern . Une modification de solution de Marc pourrait le prendre de C-style typedefs à plus comme Java-style typesafe enums. Dans cette version, les valeurs dans les constantes sont des objets de couleur dactylographiés.

Les avantages:

  • le type peut être vérifié (à l'exécution) par = = et d'autres opérations pour éviter les accidents comparaison avec les chiffres bruts ou d'autres types d'énums.
  • vous pouvez vérifier explicitement le type de vos variables (à l'exécution).
  • Les valeurs
  • sont affichées avec des noms lisibles au lieu des codes opaques.
  • les opérations comme mean() et std () qui n'ont pas de sens sur enums sont interdites.

inconvénients:

  • Plus la définition de la classe. Mais, c'est tout boilerplate, et peut être réutilisé pour n'importe quelle autre classe d'enum, en changeant juste le nom de classe et les propriétés constantes.
  • ces énums ne peuvent pas être utilisés directement dans les blocs de commutation. J'ai besoin de sortir le Code, ce qui perd un peu de sécurité.
  • Les objets
  • seront plus lents que les primitifs. Utile si vous utilisez des constantes à l'intérieur des boucles.

dans l'ensemble, je ne sais pas quelle approche est la meilleure. N'avez pas utilisé en pratique.

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

Voici une fonction pour l'exercer.

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

exemple d'utilisation:

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

>> 

une petite bizarrerie dans les deux approches: la convention C de mettre la constante sur la main gauche du "= = " pour prévenir la mauvaise affectation n'aide pas autant ici. Dans Matlab, si vous utilisez accidentellement " = " avec cette constante sur le LHS, au lieu d'une erreur, cela créera juste une nouvelle variable de structure locale appelée Colors, et cela masquer la classe enum.

>> Colors.BLUE = 42
Colors = 
    BLUE: 42
>> Color.BLUE = 42
Color = 
    BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
5
répondu Andrew Janke 2017-05-23 11:54:22

après avoir essayé les autres suggestions sur cette page, J'ai atterri sur L'approche entièrement orientée objet D'Andrew. Très agréable grâce à Andrew.

dans le cas où quelqu'un est intéressé, cependant, j'ai fait (ce que je pense être) quelques améliorations. En particulier, j'ai supprimé la nécessité de double-spécifier le nom de l'objet enum. Les noms sont maintenant dérivés en utilisant la réflexion et le système metaclass. De plus, les fonctions eq() et ismember() ont été réécrites pour donner une forme correcte valeurs de retour pour les matrices des objets enum. Enfin, la fonction check_type_safety () a été modifiée pour la rendre compatible avec les répertoires de paquets (par exemple, namespaces).

semble bien fonctionner, mais faites-moi savoir ce que vous en pensez:

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

Merci, Mason

3
répondu Mason Freed 2010-07-13 17:56:10

si vous avez accès à la boîte à outils des statistiques, vous pouvez envisager d'utiliser un objet catégorique .

3
répondu Loren 2012-02-22 16:19:14
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'};

Toys{3}
  ans = 'Rex'
2
répondu Felix Bors 2013-05-01 17:00:31

si vous avez besoin des types énumérés juste pour passer à l'Assemblée C# ou .NET, vous pouvez construire et passer les énums avec MATLAB 2010:

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

vous pouvez aussi vérifier la réponse officielle de MathWorks à

Comment puis-je utiliser les valeurs dénombrées de 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,
}
1
répondu shahar_m 2012-11-20 15:21:44