简体   繁体   中英

Representation of value class in table

If I have a value class like this:

classdef MyVal
    properties
        foo
    end
    methods 
        function self = MyVal(varargin)
            if nargin > 0
                self.foo = varargin{1};
            end
        end
    end
end

and use it in a table:

foo(1) = MyVal(1); foo(2) = MyVal(2);
t = table(foo')

the output is:

t =

  2×1 table

       Var1    
    ___________

    [1×1 MyVal]
    [1×1 MyVal]

Is there any method which has to be defined in MyVal (or any property of the table) which allows to change the representation of the value in the table? I do not want to convert the data passed to table since I'd like to retrieve instances of MyVal when I index in the table.

You could create a custom wrapper for table . This is slightly pokey because MATLAB doesn't let you inherit from the table class, but by overloading the subsref and subsasgn operators you can get most of the functionality anyway...

I've included the class at the bottom of this answer since it's a bit long, usage would look like this:

>> foo(1) = MyVal(1); foo(2) = MyVal(2);
>> t = MyTable(foo') % Omitting the ";" calls our overloaded "disp" function
t = 
    Var1
    ____
    1   
    2   

You can also use this to extract the numeric data (ie the foo property alongside other data) by using t.numeric , although I suspect you will need to use table2array on this for use with uitable , as you would with a normal table .

classdef MyTable
    properties ( Access = private )
        table_
    end
    properties ( Dependent = true )
        numeric
    end
    methods % Constructor and getter
        function obj = MyTable( varargin )
            % Store as a normal table internally
            obj.table_ = table( varargin{:} );
        end 
        function num = get.numeric( obj )
            % By calling obj.numeric, output the table but with MyVal
            % objects replaced by their "foo" property.
            % This could be passed into a uitable, and is used in disp()
            cls = varfun( @(x)isa(x,'MyVal'), obj.table_, 'OutputFormat', 'uniform' );
            num = obj.table_;
            for ii = find(cls)
                num.(num.Properties.VariableNames{ii}) = [num.(num.Properties.VariableNames{ii}).foo].';
            end            
        end
    end
    methods % Overloaded to emulate table behaviour        
        function disp( obj )
            % Overload the disp function (also called when semi colon is
            % omitted) to output the numeric version of the table
            disp( obj.numeric );
        end
        % Overload subsref and subsasgn for table indexing
        function varargout = subsref( obj, s )
            [varargout{1:nargout}] = builtin( 'subsref', obj.table_, s );
        end
        function obj = subsasgn( obj, s, varargin )
            obj.table_ = builtin( 'subsasgn', obj.table_, s, varargin{:} );
        end    
        % Have to overload size and isa for workspace preview
        function sz = size( obj, varargin )
            sz = size( obj.table_, varargin{:} );
        end
        function b = isa( obj, varargin )
            % This is only OK to do because we overloaded subsref/subsasgn
            b = isa( obj.table_, varargin{:} );
        end        
    end
end

Only a half answer

I couldn't find the way to customise the display of the table of object, but if you can get by by using arrays of object there is a way, described in Customize Object Display for Classes .

For your example, you have to derive your class with: matlab.mixin.CustomDisplay , then override the displayNonScalarObject method:

classdef MyVal < matlab.mixin.CustomDisplay
    properties
        foo
    end
    methods
        function self = MyVal(varargin)
            if nargin > 0
                self.foo = varargin{1};
            end
        end
    end
    
    methods (Access = protected)
        function displayNonScalarObject(objAry)
            dimStr = matlab.mixin.CustomDisplay.convertDimensionsToString(objAry);
            cName = matlab.mixin.CustomDisplay.getClassNameForHeader(objAry);
            headerStr = [dimStr,' ',cName,' members:'];
            header = sprintf('%s\n',headerStr);
            disp(header)
            for ix = 1:length(objAry)
                o = objAry(ix);

                % OPTION 1:
                % For a class with a sinle property, no need to call the
                % big guns, just build your own display:
                disp( [num2str(ix) ': foo = ' num2str(o.foo) ] ) ;
                
                % OR OPTION 2: (comment option1 if you use this)
                % If your class had multiple properties and you want to
                % display several of them, use the MATLAB built-in functions:
                
                % create a structure with the property names you need
                % displayed:
%                 propList = struct('foo',o.foo,'prop2',o.prop2,'prop3',o.prop3);
                % Then let MATLAB handle the display
%                 propgrp = matlab.mixin.util.PropertyGroup(propList);
%                 matlab.mixin.CustomDisplay.displayPropertyGroups(o,propgrp);
            end
        end  
    end
end

Now if you build an array of your class, the display will look like:

>> foo(1) = MyVal(1); foo(2) = MyVal(2);
>> foo
foo = 
1x2 MyVal members:

1: foo = 1
2: foo = 2

Of course this is just an example and is highly customizable. Unfortunately, I couldn't find a way to make that work for table objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM