Sorting a custom enumeration
7 views (last 30 days)
Show older comments
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{:});
0 Comments
Accepted Answer
Guillaume
on 4 Dec 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 Comments
Guillaume
on 4 Dec 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
More Answers (1)
rmiku
on 15 Jul 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. :)
0 Comments
See Also
Categories
Find more on Categorical Arrays in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!