如何在不首先将其分配给局部变量的情况下为函数返回的MATLAB数组建立索引?


363

例如,如果我想从中读取中间值magic(5),可以这样进行:

M = magic(5);
value = M(3,3);

得到value == 13。我希望能够执行以下操作之一:

value = magic(5)(3,3);
value = (magic(5))(3,3);

取消中间变量。但是,MATLAB抱怨Unbalanced or unexpected parenthesis or bracket在之前的第一个括号3

是否可以在不首先将其分配给变量的情况下从数组/矩阵读取值?


2
我还找到了有关该主题的以下文章:mathworks.com/matlabcentral/newsreader/view_thread/280225有人对此主题有新信息吗,它将实现吗?

2
实际上,此语法在Octave中可以正常工作。我只有在使用MATLAB的同事遇到运行我的代码的问题时才发现此问题。
sffc 2015年

2
简而言之,MATLAB。
user76284 '18

1
自版本6起,递归提取也可在Scilab(scilab.org)中使用。
StéphaneMottelet,19年

testmatrix('magi', 5)(3, 3)上Scilab的并magic(5)(3, 3)在倍频像神韵兼备的工作!
FOAD

Answers:


384

它实际上可以做到你想要什么,但你必须使用索引操作符的功能形式。使用进行索引操作时(),实际上是在调用该subsref函数。因此,即使您不能执行此操作:

value = magic(5)(3, 3);

可以这样做:

value = subsref(magic(5), struct('type', '()', 'subs', {{3, 3}}));

丑陋,但可能。;)

通常,您只需将索引步骤更改为函数调用,这样就不必紧接着紧跟着两组括号。做到这一点的另一种方法是定义自己的匿名函数来进行下标索引。例如:

subindex = @(A, r, c) A(r, c);     % An anonymous function for 2-D indexing
value = subindex(magic(5), 3, 3);  % Use the function to index the matrix

然而,当一切都说过和做过临时局部变量的解决方法是很多的可读性,而且肯定我的建议。


26
好吧,你知道什么!尽管我同意这很丑陋,而且可能比temp-var解决方案的可读性差。+1获得令人难忘的Matlab知识!
第二秒

57
那真是令人作呕,但答案很明确。干得好!应该已经猜到有退路了。我认为我将继续使用temp变量。
Joe Kearney 2010年

29
请记住,中间变量虽然仍然完全创建。因此,如果目的是通过不必创建临时的局部变量来节省内存,那就不用走运了。
山姆·罗伯茨

8
@SamRoberts:您不能像Matlab这样的严格评估语言来解决这个问题。人们希望这样做的主要原因是简洁/可读性,而不是节省内存。
机械蜗牛

5
@SamRoberts:的确如此,但这确实使您摆脱了召唤clear临时工的负担(这是没人能做到的)–临时工的
停留

131

只是有好的博客文章罗兰Matlab的艺术前几天有一对夫妇的宝石,这可能有助于。特别是,使用以下辅助功能:

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

paren()可以在哪里使用

paren(magic(5), 3, 3);

会回来

ans = 16

我还要猜测这将比gnovice的答案快,但是我还没有检查(使用探查器!!)。话虽如此,您还必须在某些地方包含这些函数定义。我个人已经使它们具有独立的功能,因为它们非常有用。

这些功能和其他功能现在可在“ 函数式编程构造”附加组件中找到,该附加组件可通过MATLAB附加资源管理器或在File Exchange上获得


2
这是gnovice答案的后半部分的一般版本。也不错。
Joe Kearney

myfunc().attr
Gerrit

@gerrit,如何提供帮助?除非您具有数据库工具箱,否则x.attr()字段不可用。
T. Furfaro

@ T.Furfaro嗯?如果myfunc()返回的结构包括一个属性attr,那么要访问attr当前我需要做的S = myfunc(); S.attr。问题是我们是否可以具有getattr(myfunc(), 'attr')类似于parenand curly帮助器的帮助器功能。我不知道这与数据库工具箱有什么关系。
Gerrit

2
@gerrit抱歉,完全混乱(我不知道您的“ attr”是任意的-在db tb中明确定义了这样的字段)。我相信您正在寻找的是getfield()
T. Furfaro 2013年

75

您对使用未公开记录的功能有何看法:

>> builtin('_paren', magic(5), 3, 3)               %# M(3,3)
ans =
    13

或单元格数组:

>> builtin('_brace', num2cell(magic(5)), 3, 3)     %# C{3,3}
ans =
    13

就像魔术:)


更新:

坏消息是,上述破解在R2015b中不再起作用!很好,这是未记录的功能,我们不能依靠它作为受支持的功能:)

对于那些想在哪里找到这种东西的人,请查看文件夹fullfile(matlabroot,'bin','registry')。那里有一堆XML文件,其中列出了各种各样的东西。请注意,直接调用其中一些函数可能会轻易使您的MATLAB会话崩溃。


@RodyOldenhuis:我现在不记得了,我想我一定已经读过一些埋藏的代码了;)
Amro

2
必须将冒号(:)运算符与撇号':'一起使用,以避免出现error Undefined function or variable "builtin"
多米尼克2014年

@Dominik:对,说要切片与第2列,这将是:builtin('_paren', magic(5), ':', 2)(在某些地方直接做工作,而报价的:,而不是':'从一个函数内部在命令提示符下直接运行的时候不一样,我猜。 (解析器中的错误!)
Amro

2
我不认为有某种方法可以使用end
knedlsepp 2015年

2
@knedlsepp:否,不幸的是,整个end-trickery不能在此语法下工作,您必须在索引中明确显示此信息。(相同的限制适用于所列出的大多数其他答案)
Amro


15

不幸的magic(5)(3,3)是,matlab不支持like之类的语法。您需要使用临时中间变量。您可以在使用后释放内存,例如

tmp = magic(3);
myVar = tmp(3,3);
clear tmp

12

请注意,如果将运行时间与标准方法(分配结果然后访问条目)进行比较,则它们是完全相同的。

subs=@(M,i,j) M(i,j);
>> for nit=1:10;tic;subs(magic(100),1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0103

>> for nit=1:10,tic;M=magic(100); M(1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0101

在我看来,最重要的是:MATLAB没有指针,必须忍受它。


6

如果您创建一个新功能,可能会更简单:

function [ element ] = getElem( matrix, index1, index2 )
    element = matrix(index1, index2);
end

然后使用它:

value = getElem(magic(5), 3, 3);

1
但这subref确实是...但是以更一般的方式。
Shai)

2
是的,更一般的方法,但不友好...我认为这很难看。
Vugar)

4

您的初始符号是执行此操作的最简洁的方法:

M = magic(5);  %create
value = M(3,3);  % extract useful data
clear M;  %free memory

如果您是循环执行此操作,则可以每次都重新分配M,也可以忽略clear语句。


6
我同意这是更简洁的方法,正如您所说,清除是一个循环的好主意,但是问题特别是是否可以避免中间分配。
乔·科尔尼

1

为了补充Amro的答案,您可以使用feval代替builtin。除非您尝试重载运算符功能,否则没有任何区别:

BUILTIN(...)与FEVAL(...)相同,不同之处在于,即使存在重载的函数,它也会调用该函数的原始内置版本(为此,必须永远不要重载BUILTIN)。

>> feval('_paren', magic(5), 3, 3)               % M(3,3)
ans =
    13

>> feval('_brace', num2cell(magic(5)), 3, 3)     % C{3,3}
ans =
    13

有趣的是,至少在Matlab 2013b中,这feval似乎比builtin(〜3.5%)快了一点,这很奇怪,因为feval需要检查函数是否已重载,这与之不同builtin

>> tic; for i=1:1e6, feval('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 49.904117 seconds.
>> tic; for i=1:1e6, builtin('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 51.485339 seconds.

这实际上并不奇怪:MATLAB保留了已定义函数的列表,没有太多要做的搜索。feval做“正常”事情,因此可以充分利用此列表。builtin必须在其他地方搜索,因此只能找到内置函数。这种情况可能没有像“正常”情况那样优化,因为您为什么要花钱来优化一些不经常使用的东西?
Cris Luengo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.