Effacer les filtres
Effacer les filtres

Sorting a custom enumeration

4 vues (au cours des 30 derniers jours)
Simon Parten
Simon Parten le 4 Déc 2018
Réponse apportée : rmiku le 15 Juil 2021
For various reasons, I want to be able to define an enumeration. This enumeration will have some properties. I'd also like to be able to use it as a key.
Undefined function 'sort' for input arguments of type 'MyGreatEnum'.
However, methods like 'unique' don't work, which is strange for me, as there is clearly a well defined set of unique enums in a list of enums, that are from the same class.
Any ideas?
i.e. I'd like to do
events
events =
2×1 MyGreatEnum enumeration array
MyGreatEnum1
MyGreatEnum2
unique(events)
Error using sort
Undefined function 'sort' for input arguments of type 'MyGreatEnum'.
Error in unique>uniqueR2012a (line 211)
sortA = sort(a);
Error in unique (line 103)
[varargout{1:nlhs}] = uniqueR2012a(varargin{:});

Réponse acceptée

Guillaume
Guillaume le 4 Déc 2018
You should be able to sort your enumeration class if you derive it from a numeric class:
classdef myGreatEnum < double
enumeration
myGreatEnum1 (1)
myGreatEnum2 (2)
myGreatEnum3 (3)
myGreatEnum4 (4)
myGreatEnum5 (5)
myGreatEnum6 (6)
myGreatEnum7 (7)
myGreatEnum8 (8)
myGreatEnum9 (9)
end
end
>> events = [myGreatEnum.myGreatEnum1, myGreatEnum.myGreatEnum5, myGreatEnum.myGreatEnum2, myGreatEnum.myGreatEnum5];
>> unique(events)
ans =
1×3 myGreatEnum enumeration array
myGreatEnum1 myGreatEnum2 myGreatEnum5
Personally, I don't like the way enumerations are implemented in matlab. I would recommend that you use ordinal categorical arrays instead of enums.
>> events = categorical([1 5 2 5], 1:9, compose('MyGreatEnum%d', 1:9), 'Ordinal', true)
events =
1×4 categorical array
MyGreatEnum1 MyGreatEnum5 MyGreatEnum2 MyGreatEnum5
>> unique(events)
ans =
1×3 categorical array
MyGreatEnum1 MyGreatEnum2 MyGreatEnum5
  2 commentaires
Simon Parten
Simon Parten le 4 Déc 2018
Hmmm... hard to argue with your statement on enums - they do appear somewhat hamstrung.
In this case, the natural order would be a string, However, char, string, and categorical are all sealed.
I'll have a think about categorical. Thanks for the response.
Guillaume
Guillaume le 4 Déc 2018
Yes, with enumerations you cannot derive from any of the string type. However, since you have a finite number of values, you can just replace your lexicographic ordering by a matching numerical ordering.
If you want a lexicographic ordering, it's easy to get that with categorical arrays. You don't even need it to be ordinal if you're just interested in sort and unique:
>> events = categorical({'event1', 'event2', 'event1'}, compose('event%d', 1:9))
events =
1×3 categorical array
event1 event2 event1
>> unique(events)
ans =
1×2 categorical array
event1 event2
>> sort(events)
ans =
1×3 categorical array
event1 event1 event2

Connectez-vous pour commenter.

Plus de réponses (1)

rmiku
rmiku le 15 Juil 2021
I believe I have a better option: overload the built-in sort() function in your enumeration definition.
I built out your enumeration to have a few properties. This is how I ran into your issue.
classdef myGreatEnum
enumeration
% a b c
mGE1 (1, 2, 3)
mGE2 (4, 5, 6)
mGE3 (7, 8, 9)
end
properties
a
b
c
end
methods
function enum = myGreatEnum(varargin)
% Default constructor, sets properties
if(nargin == 3)
% Enumeration definitions are dependent on this order
% don't rearrange this without changing the enumerations
enum.a = varargin{1};
enum.b = varargin{2};
enum.c = varargin{3};
end
end
function [B, idx] = sort(varargin)
% Overloaded function for the builtin sort() function
t = varargin{1};
varargin{1} = string(varargin{1}); % Using varargin allows us to still pass arguments like sort order "descend" into the builtin function
[~, idx] = sort(varargin{:}); % Sort based on the enum names (varargin{1})
B = t(idx);
end
end
end
I chose to sort my enumeration based on the alphabetic enum name. You could just as easily change it to sort on something like peroperty 'a', by using:
function [B, idx] = sort(varargin)
t = varargin{1};
varargin{1} = varargin{1}.a;
[~, idx] = sort(varargin{:}); % Sort based on the enum 'a' properties
B = t(idx);
end
The cool thing is that a structure like this allows you to do things like:
>> myGreatEnum.mGE2.a
ans =
4
or something like:
>> events = [myGreatEnum.mGE2; myGreatEnum.mGE3; myGreatEnum.mGE2]
>> events(1).a
ans =
4
Anyways, now that the sort() function is overloaded to sort on the enum names (mGE1, mGE2, mGE3, etc....), we can call sort(), or even unique():
>> events = [myGreatEnum.mGE2; myGreatEnum.mGE3; myGreatEnum.mGE2] % Creating the array like you had
events =
3x1 myGreatEnum enumeration array
mGE2
mGE3
mGE2
>> sort(events)
ans =
3x1 myGreatEnum enumeration array
mGE2
mGE2
mGE3
>> unique(events)
ans =
2x1 myGreatEnum enumeration array
mGE2
mGE3
we can even get some of the extended sort() capabilites, like passing in arguments, or getting the indices
>> sort(events, 'descend')
ans =
3x1 myGreatEnum enumeration array
mGE3
mGE2
mGE2
>> [B, I] = sort(events, 'descend')
B =
3x1 myGreatEnum enumeration array
mGE3
mGE2
mGE2
I =
2
1
3
Pretty cool! I understand this post may be a little late, but hopefully it will help someone in the future. :)

Catégories

En savoir plus sur Categorical Arrays dans Help Center et File Exchange

Produits


Version

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by