【问题标题】:Updating one field in every element of a Matlab struct array更新 Matlab 结构数组的每个元素中的一个字段
【发布时间】:2012-02-15 23:17:24
【问题描述】:

假设我有一个结构数组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{:});

有什么想法吗?谢谢。

【问题讨论】:

    标签: arrays matlab struct field assign


    【解决方案1】:

    请注意,这里不需要deal:

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

    我知道如何做到这一点的唯一其他方法(没有 foo 循环)是使用 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 循环效率低,因为它返回一个 copy 的 arr,而不是就地操作。

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

    【讨论】:

    • 感谢deal 的提示。我不知道setfield,所以这似乎是在一行中完成的,但正如你所说,这肯定比 for 循环解决方案更糟糕。至于这样的索引,我前段时间研究过;基本上,Mathworks 声称支持任何类似的东西都会强制对解析器进行破坏兼容性的更改。真可惜,因为几乎每次我编写任何 Matlab 代码时都会让我烦恼。
    • 感谢您的回答!在 MATLAB 2013b 中,[arr.val] = newVals{:} 有效,但 arr.val = newVals{:}。在这种情况下,括号究竟有什么作用?
    • arrayfun 只是 MATLAB 中 for 循环的包装器,因此从技术上讲,您仍在使用循环,尽管是伪装的。
    • deal 对结构数组有用的一种情况是,当您想为结构数组的每个元素的字段分配相同的值时。例如v = 9,你可以写[arr.val] = deal(v);,将9赋给struct数组arr的每个元素的val字段。
    • [arr.val] = newVals{:}; 有效,但 [arr.val] = newVals(:); 无效 - 也就是说,如果 newVals 是向量而不是单元阵列。谁能解释一下?!
    【解决方案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));  
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        如果您要设置的struct数组是一组图形对象(线句柄、图形句柄、轴句柄等),那么您需要使用函数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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-06-01
          • 2015-02-21
          • 1970-01-01
          • 2014-11-03
          • 2023-03-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多