我在mathworks博客上阅读了关于matlab中函数式编程的this article,其中有两个辅助函数:
paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};
完成三重奏的明显第三个(并与五个字母的主题保持一致)将是:
acces = @(x, field) x.(field);
讨论在matlab中以这种方式实现链接是否是一个好主意(注意:octave默认支持链接),paren
似乎运行良好,如预期的那样;但是,curly
和acces
有一个主要缺点;请考虑以下代码:
>> 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与octave中返回内容,和/或 b。如何序列是用两种语言的单元格和结构生成的。
但是,是否有一种编程方式让matlab执行上述预期操作?
换句话说,有没有办法定义返回序列的curly
和acces
函数(匿名函数的额外奖励:p)像八度音程一样?
上在线测试最新的matlab
答案 0 :(得分:4)
免责声明:较少的答案和更多的随机沉思
这里的问题是,在MATLAB中,单个函数(匿名或其他)无法以点引用和{}
索引的方式返回逗号分隔列表。
即使是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中单个函数可以做什么,返回多个输出。这正是subsref
和其他内置函数返回您希望的多个值的方式
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');
不幸的是,你无法在匿名函数中执行此操作,并且除了通过对{{的后续调用包装它之外,还没有简单的方法来获取非单元格数组。 1}}
cell2mat
你可以创建一些匿名函数来执行这些不同的操作,但它们很混乱。
[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
但真正的解决方案只是使用一个临时变量,然后使用典型的MATLAB语法将其索引:)
% This is really just using parenthesis
curly_sequence_cell = paren;
curly_sequence_array = @(varargin)cell2mat(paren(varargin{:}));