Implementing 'curly' and 'access' “chaining” functions in matlab

后端 未结 1 1117
春和景丽
春和景丽 2021-01-20 22:35

I read this article on the mathworks blog about functional programming in matlab, and two of the helper functions there were:

paren = @(x, varargin) x(vararg         


        
1条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-20 23:01

    Disclaimer: Less of an answer and more of some random musings

    The issue here is that, in MATLAB, a single function (anonymous or otherwise) is incapable of returning a comma-separated list the way that dot referencing and {} indexing can.

    Even MATLAB's internal functions for performing the referencing are incapable of doing so:

    subsref(S, substruct('.', 'name'))
    %   john
    
    builtin('_dot', S, 'name')              % Only works pre-2015b
    %   jim
    
    subsref(C, substruct('{}', {3 ':'}))
    %   3
    
    builtin('_brace', C, 3, ':')            % Only works pre-2015b
    %   3
    

    But what a single function can do in MATLAB, is return multiple outputs. This is precisely how subsref and the other built-ins return the multiple values you're hoping for

    S = struct('name', {'john', 'jim'});
    
    [val1, val2] = subsref(S, substruct('.', 'name'));
    [val1, val2] = builtin('_dot', S, 'name');
    
    C = num2cell(magic(3));
    
    [val1, val2, val3] = subsref(C, substruct('{}', {3, ':'}));
    [val1, val2, val3] = builtin('_brace', C, 3, ':');
    

    Now this doesn't really help your helper anonymous function since it requires knowledge of how many outputs to expect and that in turn depends on the inputs.

    For your acces function, it's relatively straight forward to determine the number of outputs so you could easily do something like:

    [A{1:numel(S)}] = acces(S, 'name');
    

    Unfortunately, you can't do that inside of an anonymous function, and there's also no easy way to get a non-cell array out apart from wrapping this with a follow-up call to cell2mat

    [A{1:numel(S)}] = acces(S, 'name');
    A = cell2mat(A);
    

    You could create some anonymous functions to do these various operations, but they are messy.

    access_cell = @(s,n)arrayfun(@(x)acces(x,n), s, 'uniform', 0);
    access_array = @(s,n)arrayfun(@(x)acces(x,n), s, 'uniform', 1);
    

    As for your curly you could instead use paren to grab a subset of the cell array as a cell and then loop through it with cellfun to yield the result.

    % This is really just using parenthesis
    curly_sequence_cell = paren;
    
    curly_sequence_array = @(varargin)cell2mat(paren(varargin{:}));
    

    But the real solution is just use a temporary variable and then index into that using the typical MATLAB syntax :)

    S = struct('name', {'john', 'jim'});
    A = {S.name};
    

    0 讨论(0)
提交回复
热议问题