在matlab中实现'curly'和'access'"chaining"函数

Implementing 'curly' and 'access' "chaining" functions in matlab

我在 mathworks 博客上阅读 this article 关于 matlab 函数式编程的内容,其中两个辅助函数是:

paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};

完成三重奏(并与五个字母的主题保持一致)的明显第三个是:

acces = @(x, field) x.(field);

将关于在 matlab 中以这种方式实现链接是否是一个好主意的讨论放在一边(注意:octave 默认支持链接),paren 似乎工作得很好,正如预期的那样;但是,curlyacces 有一个主要缺点;考虑以下代码:

>> C = {1,2,3,4; 2,3,4,5; 3,4,5,6; 4,5,6,7};
>> A = [curly(C, 3, ':')]
A =
     3

即预期的 序列 生成没有发生。
(请注意,此代码在 Octave 中按预期工作,即 A = [3,4,5,6]

同样,acces在matlab中不产生序列

>> S = [struct('name', 'john'), struct('name', 'jim')];
>> A = {acces(S, 'name')}
A = 
    'john'

(而 Octave 产生预期的 A = {'john', 'jim'}

我知道区别可能更多的是 a 方面的实现问题。 matlab 与八度音程中的 return 功能如何,and/or b. 如何从两种语言的单元格和结构生成序列。

但是,有没有一种编程方式可以让 matlab 执行上面的预期操作?
换句话说,有没有办法像八度一样定义 curlyacces 一个序列的 return 函数(匿名函数的额外奖励 :p )?


PS。我正在寻找的答案不是微不足道的 "to get multiple arguments out use varargout"一个.
PS2。 我在 Matlab 2013b 上对此进行了测试,所以我不知道此行为是否已在更高版本中 "fixed"(尽管我非常怀疑)。 在最新的 matlab 在线测试http://matlab.mathworks.com

免责声明:少了一个答案,多了一些随意的思考

这里的问题是,在 MATLAB 中,单个函数(匿名或其他)无法像点引用和 {} 索引那样 returning 逗号分隔列表。

即使是 MATLAB 执行引用的内部函数也不能这样做:

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

但是 在 MATLAB 中,单个函数 可以 做的是 return 多个输出。这正是 subsref 和其他内置函数 return 您所希望的多个值的方式

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, ':');

现在这并不能真正帮助您的辅助匿名函数,因为它需要了解预期的输出数量,而这又取决于输入。

对于您的 acces 函数,确定输出数量相对简单,因此您可以轻松地执行以下操作:

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

不幸的是,您不能在匿名函数内部执行此操作,而且除了通过后续调用 cell2mat[ 包装它之外,也没有简单的方法来获取非单元格数组=24=]

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

可以创建一些匿名函数来执行这些不同的操作,但它们很混乱。

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

至于您的 curly,您可以改为使用 paren 获取单元格数组的一个子集作为单元格,然后使用 cellfun 循环遍历它以产生结果。

% This is really just using parenthesis
curly_sequence_cell = paren;

curly_sequence_array = @(varargin)cell2mat(paren(varargin{:}));

但是真正的解决方案只是使用一个临时变量,然后使用典型的 MATLAB 语法对其进行索引:)

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