在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
似乎工作得很好,正如预期的那样;但是,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 与八度音程中的 return 功能如何,and/or b. 如何从两种语言的单元格和结构生成序列。
但是,有没有一种编程方式可以让 matlab 执行上面的预期操作?
换句话说,有没有办法像八度一样定义 curly
和 acces
一个序列的 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};
我在 mathworks 博客上阅读 this article 关于 matlab 函数式编程的内容,其中两个辅助函数是:
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 与八度音程中的 return 功能如何,and/or b. 如何从两种语言的单元格和结构生成序列。
但是,有没有一种编程方式可以让 matlab 执行上面的预期操作?
换句话说,有没有办法像八度一样定义 curly
和 acces
一个序列的 return 函数(匿名函数的额外奖励 :p )?
PS。我正在寻找的答案不是微不足道的 "to get multiple arguments out use varargout"一个.
PS2。
免责声明:少了一个答案,多了一些随意的思考
这里的问题是,在 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};