【问题标题】:How can I index a MATLAB array returned by a function without first assigning it to a local variable?如何在不首先将其分配给局部变量的情况下索引函数返回的 MATLAB 数组?
【发布时间】:2011-04-07 07:50:54
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 我还找到了关于这个主题的以下文章:mathworks.com/matlabcentral/newsreader/view_thread/280225有人有关于这个主题的新信息,会实现吗?
  • 这个语法实际上在 Octave 中运行良好。我只是在使用 MATLAB 的同事在运行我的代码时遇到问题时才发现这个问题。
  • MATLAB 简而言之。
  • 递归提取也适用于 Scilab (scilab.org) 版本 6。
  • Scilab 上的 testmatrix('magi', 5)(3, 3) 和 Octave 上的 magic(5)(3, 3) 都像魅力一样工作!

标签: matlab indexing matrix return-value variable-assignment


【解决方案1】:

实际上可以做你想做的,但你必须使用索引运算符的函数形式。当您使用() 执行索引操作时,实际上是在调用subsref 函数。所以,即使你不能这样做:

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

可以这样做:

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

丑陋,但可能。 ;)

一般来说,您只需将索引步骤更改为函数调用,这样您就不会有两组括号紧随其后。另一种方法是定义您自己的anonymous function 来进行下标索引。例如:

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

然而,总而言之,临时局部变量解决方案更具可读性,这绝对是我的建议。

【讨论】:

  • 你知道什么!虽然我同意它非常丑陋,并且可能比 temp-var 解决方案更不可读。 +1 令人印象深刻的晦涩的 matlab 知识!
  • 这很恶心,但答案很明确。干得好!应该已经猜到会有回路。我想我会继续使用 temp 变量。
  • 请记住,中间变量仍然是完全创建的。因此,如果目的是通过不必创建临时局部变量来节省内存,那就没有运气了。
  • @SamRoberts:你无法用像 Matlab 这样的严格评估语言来解决这个问题。人们想要这个的主要原因是简洁/可读性,而不是节省内存。
  • @SamRoberts: 是的,但它确实使您免于在临时电话上调用clear 的负担(从来没有人这样做过)-- 临时电话倾向于停留更长时间
【解决方案2】:

几天前,Loren on the Art of Matlab 上的 good blog post 有一些可能会有所帮助的宝石。特别是,使用如下辅助函数:

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

paren() 可以像这样使用

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

会回来

ans = 16

我也推测这会比 gnovice 的答案更快,但我没有检查(使用分析器!!!)。话虽如此,您还必须在某处包含这些函数定义。我个人在我的路径中使它们成为独立的功能,因为它们非常有用。

这些函数和其他函数现在可在 Functional Programming Constructs 插件中使用,该插件可通过 MATLAB Add-On Explorer 或File Exchange 获得。

【讨论】:

  • 这是gnovice答案后半部分的稍微更一般的版本;也不错。
  • myfunc().attr 呢?
  • @gerrit,at 有什么帮助?除非您有数据库工具箱,否则 x.attr() 字段不可用。
  • @T.Furfaro 嗯?如果myfunc() 返回一个包含属性attr 的结构,那么要访问attr,目前我需要做S = myfunc(); S.attr。问题是我们是否可以有一个类似于parencurly 助手的助手函数,如getattr(myfunc(), 'attr')。我不明白这与数据库工具箱有什么关系。
  • @gerrit 抱歉,完全混乱(我不知道您的“attr”是任意的——在 db tb 中有这样一个明确定义的字段)。我相信你要找的是getfield()
【解决方案3】:

您如何看待使用未记录的功能:

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

或者对于元胞数组:

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

就像魔术一样:)


更新:

坏消息,上面的 hack 在 R2015b 中不再起作用了!没关系,它是未记录的功能,我们不能依赖它作为支持的功能:)

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

【讨论】:

  • @RodyOldenhuis:我现在不记得了,我想我一定是在一些隐藏的代码中读过它;)
  • 冒号 (:) 运算符必须与撇号 ':' 一起使用,以避免出现错误 Undefined function or variable "builtin"
  • @Dominik: 对,假设你想分割第二列,那就是:builtin('_paren', magic(5), ':', 2)(在某些地方它确实可以在没有引号的情况下直接使用:,而不是':' ,就像直接在命令提示符下运行而不是从函数内部一样。我猜这是解析器中的一个错误!)
  • 我不认为有什么方法可以使用 end 这个吗?
  • @knedlsepp:不,不幸的是整个end-trickery 在这种语法中不起作用,您必须在索引中明确说明..(同样的限制适用于大多数其他列出的答案)
【解决方案4】:

至少在 MATLAB 2013a 中您可以使用 getfield 之类的:

a=rand(5);
getfield(a,{1,2}) % etc

获取(1,2)处的元素

【讨论】:

  • 这其实是一个不错的方法。有什么缺点吗?
  • @mmumboss:这是未记录的行为,此功能可能会在未来版本中消失,恕不另行通知。除此之外没有缺点。
  • 从 MATLAB2017b 开始,此功能已记录在案。
  • 如何获得输出的一列或一行?如a(1, :)。我试过 getfield(rand(5), {1, 1:5})getfield(rand(5), {1:5, 1}) 工作正常,但不优雅。
【解决方案5】:

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

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

【讨论】:

    【解决方案6】:

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

    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 没有指针,你必须忍受它。

    【讨论】:

      【解决方案7】:

      如果你做一个新功能可能会更简单:

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

      然后使用它:

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

      【讨论】:

      • 但这正是subref 所做的……但以更一般的方式。
      • 是的,更一般的方式,但不友好......在我看来非常丑陋。
      【解决方案8】:

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

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

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

      【讨论】:

      • 我同意这更简洁,正如你所说,在循环中清除是一个好主意,但问题是具体是否可以避免中间分配。
      • clear 语句会显着降低您的代码速度,最好不要使用它,除非M 非常大并且您的某个地方内存不足。
      • @JoeKearney 明白了。也许这是我的 Matlab 新手级别,但是在给出的每个答案中都会计算中间值,即使只是在某些答案中隐含。那是对的吗?无论如何,感谢您的反馈!
      【解决方案9】:

      为了补充 Amro 的答案,您可以使用 feval 而不是 builtin。真的没有区别,除非你尝试重载操作符函数:

      BUILTIN(...) 与 FEVAL(...) 相同,只是它将调用 函数的原始内置版本,即使是重载的 存在(为此,您绝不能超载 内置)。

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

      有趣的是feval 似乎比builtin 快一点点(约3.5%),至少在Matlab 2013b 中,这很奇怪,因为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 必须在别处搜索,所以它只能找到内置函数。这种情况可能没有像“正常”情况那样优化,因为你为什么要花钱优化不经常使用的东西?
      猜你喜欢
      • 2023-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多