Updating one field in every element of a Matlab st

2019-01-14 21:40发布

问题:

Suppose I have a struct array arr, where each element has a bunch of fields, including one called val. I'd like to increment each element's val field by some constant amount, like so:

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

This obviously works, but I feel there should be a way to do this in just one line of code (and no for loop). The best I've come up with is two lines and requires a temp variable:

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

Any ideas? Thanks.

回答1:

Just a note, the deal isn't necessary there:

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

The only other way I know how to do this (without the foor loop) is using arrayfun to iterate over each struct in the array:

% 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)

That last command loops over each struct in arr and returns a new one where s.val has been set to s.val=3.

I think this is actually less efficient than your previous two-liner and the for loop though, because it returns a copy of arr as opposed to operating in-place.

(It's a shame Matlab doesn't support layered indexing like [arr.val]=num2cell([arr.val]+3){:}).



回答2:

Are all the fields in that struct scalar, or the same size? If so, the idiomatic Matlab way to do this is to rearrange your struct to be a scalar struct with arrays in each of its fields, instead of an array of structs with scalar values in the fields. Then you can do vectorized operations on the fields, like arr.val = arr.val + 3;. See if you can rearrange your data. Doing it this way is much more efficient in both time and memory; that's probably why Matlab doesn't provide convenient syntax for operating over fields of arrays of structs.



回答3:

if the struct array you are trying to set is a set of graphics objects (line handles, figure handles, axes handles, etc), then you need to use the function 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