Everytime I try editing arrays of structs by field, I discover I really need to take a few weeks and try to really learn Matlab. Right now, I have an array of structs, where each struct has fields along the line of:
x.fruit, x.color, x.season, x.source, x.flibbertigibbet
each of these fields is a string. I also have an cell array of strings:
y = {'apple', 'banana', 'palm of granite'}
I would like to remove all struct where x.fruit is in y (e.g. x.fruit == 'apple'), but can't seem to find a way to do this other than by looping through y.
I was hoping for something along the lines of:
bad_idx = [x(:).fruit in y];
x(bad_idx) = [];
Is this doable? Is there someway to use cellfun to do this?
If each element of x
only contains a string for the fruit
field, you can easily do this the following way.
toremove = ismember({x.fruit}, 'apple')
x(toremove) = [];
Or more briefly
x = x(~ismember({x.fruit}, 'apple'));
The {x.fruit}
syntax combines all of the values of fruit
for each struct
into a cell array. You can then use ismember
on the cell array of strings to compare each one to 'apple'
. This will yield a logical array the size of x
that can be used to index into x
.
You could also use something like strcmp
instead of ismember
above.
x = x(~strcmp({x.fruit}, 'apple'));
Update
If each x(k).fruit
contains a cell array, then you can use an approach similar to the above approach combined with cellfun
.
x(1).fruit = {'apple', 'orange'};
x(2).fruit = {'banana'};
x(3).fruit = {'grape', 'orange'};
x = x(~cellfun(@(fruits)ismember('apple', fruits), {x.fruit}));
%// 1 x 2 struct array with fields:
%// fruit
If you want to check for multiple types of fruit to remove at once, you could do something like.
%// Remove if EITHER 'apple' or 'banana'
tocheck = {'apple', 'banana'};
x = x(~cellfun(@(fruits)any(ismember({'apple', 'banana'}, fruits)), {x.fruit}));
%// Remove if BOTH 'apple' and 'banana' in one
x = x(~cellfun(@(fruits)all(ismember({'apple', 'banana'}, fruits)), {x.fruit}));