23

假设我有一个 struct array arr,其中每个元素都有一堆字段,包括一个名为val. 我想将每个元素的val字段增加一些常数,如下所示:

for i = 1:length(arr)
    arr(i).val = arr(i).val + 3;
end

这显然有效,但我觉得应该有一种方法可以在一行代码中做到这一点(并且没有 for 循环)。我想出的最好的是两行,需要一个临时变量:

newVals = num2cell([arr.val] + 3);
[arr.val] = deal(newVals{:});

有任何想法吗?谢谢。

4

4 回答 4

13

请注意,deal那里没有必要:

[arr.val] = newVals{:}; % achieves the same as deal(newVals{:})

我知道如何做到这一点的唯一另一种方法(没有 foror 循环)是使用arrayfun迭代数组中的每个结构:

% make a struct array
arr = [ struct('val',0,'id',1), struct('val',0,'id',2), struct('val',0,'id',3) ]

% some attempts
[arr.val]=arr.val; % fine
[arr.val]=arr.val+3; % NOT fine :(

% works !
arr2 = arrayfun(@(s) setfield(s,'val',s.val+3),arr)

最后一个命令遍历每个结构arr并返回一个s.val已设置为的新结构s.val=3

我认为这实际上比你之前的两行和 for 循环效率低,因为它返回一个副本arr不是就地操作。

(遗憾的是,Matlab 不支持像 那样的分层索引[arr.val]=num2cell([arr.val]+3){:})。

于 2012-02-16T00:43:24.803 回答
2

我喜欢 Carl 和 math.coffee 的原创想法。我有多个类似的行要表达,所以为了简洁我的主线代码,我继续制作通用子函数

function varargout = clist(in)
varargout = {in{:}};
end

然后我可以以相当易读的方式表达每一行

[arr.var]  = clist(num2cell([arr.var]+3));  
[arr.var2] = clist(num2cell([arr2.var]/5+33));  
于 2020-10-27T22:30:04.693 回答
1

该结构中的所有字段都是标量还是相同大小?如果是这样,执行此操作的惯用 Matlab 方法是将您的结构重新排列为在其每个字段中具有数组的标量结构,而不是在字段中具有标量值的结构数组。然后您可以对字段进行矢量化操作,例如arr.val = arr.val + 3;. 看看你是否可以重新排列你的数据。这样做在时间和内存上都更有效;这可能就是为什么 Matlab 没有提供方便的语法来操作结构数组的字段。

于 2012-02-16T01:40:00.620 回答
0

如果您尝试设置的结构数组是一组图形对象(线句柄、图形句柄、轴句柄等),那么您需要使用该函数set

x = (1:10)';
Y = rand(10,5);
l = plot(x,Y,'-k'); % returns an array of line handles in l
set(l,'Color','r'); % sets the property 'Color' for all the five lines in l
于 2017-01-27T19:43:05.057 回答