ChatGPT解决这个技术问题 Extra ChatGPT

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

例如,如果我想从 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。
自版本 6 起,递归提取也适用于 Scilab (scilab.org)。
Scilab 上的 testmatrix('magi', 5)(3, 3) 和 Octave 上的 magic(5)(3, 3) 都像一个魅力!

g
gnovice

它实际上可以做你想做的,但你必须使用索引运算符的功能形式。当您使用 () 执行索引操作时,实际上是在调用 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 的负担(从来没有人这样做过)——临时往往会停留更长时间
n
nekomatic

几天前在 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,如何提供帮助?除非您拥有数据库工具箱,否则 x.attr() 字段不可用。
@T.Furfaro 嗯?如果 myfunc() 返回一个包含属性 attr 的结构,那么要访问 attr,目前我需要执行 S = myfunc(); S.attr。问题是我们是否可以有一个类似于 parencurly 辅助函数的辅助函数,如 getattr(myfunc(), 'attr')。我不明白这与数据库工具箱有什么关系。
@gerrit抱歉,完全混乱(我不知道您的“attr”是任意的-在db tb中明确定义了这样一个字段)。我相信您正在寻找的是getfield()
A
Amro

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

>> 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 在这种语法中不起作用,您必须在索引中明确说明..(同样的限制适用于大多数其他列出的答案)
C
Cris Luengo

至少在 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}) 工作正常,但不优雅。
@ZRHan:您可以使用 getfield(rand(5), {1, ':'})
s
second

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

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

u
user

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

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


S
Shai

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

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

然后使用它:

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

但这正是 subref 所做的......但以更一般的方式。
是的,更一般的方式,但不友好......在我看来非常丑陋。
A
Andreas GS

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

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

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


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

为了补充 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

有趣的是,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 必须在别处搜索,以便只找到内置函数。这种情况可能没有像“正常”情况那样优化,因为你为什么要花钱优化不经常使用的东西呢?

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅