2

Here's a non-scalar structure in matlab:

clearvars s
s=struct;
for id=1:3
s(id).wa='nko';
s(id).test='5';
s(id).ad(1,1).treasurehunt='asdf'
s(id).ad(1,2).treasurehunt='as df'
s(id).ad(1,3).treasurehunt='foobar'
s(id).ad(2,1).treasurehunt='trea'
s(id).ad(2,2).treasurehunt='foo bar'
s(id).ad(2,3).treasurehunt='treasure'
s(id).ad(id,4).a=magic(5);
end

is there an easy way to test if the structure s contains the string 'treasure' without having to loop through every field (e.g. doing a 'grep' through the actual content of the variable)?

The aim is to see 'quick and dirtily' whether a string exists (regardless of where) in the structure. In other words (for Linux users): I'd like to use 'grep' on a matlab variable.

I tried arrayfun(@(x) any(strcmp(x, 'treasure')), s) with no success, output:

ans =

  1×3 logical array

   0   0   0
user2305193
  • 2,079
  • 18
  • 39

3 Answers3

2

This is one way to avoid an explicit loop

% Collect all the treasurehunt entries into a cell with strings
s_cell={s(1).ad.treasurehunt, s(2).ad.treasurehunt, s(3).ad.treasurehunt};
% Check if any 'treasure 'entries exist
find_treasure=nonzeros(strcmp('treasure', s_cell));
% Empty if none
if isempty(find_treasure)
    disp('Nothing found')
else
    disp(['Found treasure ',num2str(length(find_treasure)), ' times'])
end

Note that you can also just do

% Collect all the treasurehunt entries into a cell with strings
s_cell={s(1).ad.treasurehunt, s(2).ad.treasurehunt, s(3).ad.treasurehunt};
% Check if any 'treasure 'entries exist
find_treasure=~isempty(nonzeros(strcmp('treasure', s_cell)));

..if you're not interested in the number of occurences

atru
  • 4,699
  • 2
  • 18
  • 19
2

One general approach (applicable to any structure array s) is to convert your structure array to a cell array using struct2cell, test if the contents of any of the cells are equal to the string 'treasure', and recursively repeat the above for any cells that contain structures. This can be done in a while loop that stops if either the string is found or there are no structures left to recurse through. Here's the solution implemented as a function:

function found = string_hunt(s, str)
  c = reshape(struct2cell(s), [], 1);
  found = any(cellfun(@(v) isequal(v, str), c));
  index = cellfun(@isstruct, c);
  while ~found && any(index)
    c = cellfun(@(v) {reshape(struct2cell(v), [], 1)}, c(index));
    c = vertcat(c{:});
    found = any(cellfun(@(c) isequal(c, str), c));
    index = cellfun(@isstruct, c);
  end
end

And using your sample structure s:

>> string_hunt(s, 'treasure')

ans =

  logical

   1        % True!
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • I was thinking more of something like typecasting the struct to string, then searching it. Could you think of an easy solution based on that approach? Basically I'd like to use 'grep' on a matlab variable. – user2305193 Aug 28 '17 at 09:01
  • 1
    @user2305193: There's no simple way to typecast a `struct` to another type, since it's really a container class as opposed to a data type. Any conversion would have to recurse through the whole depth, while the above solution stops recursing once it finds a match at a given depth, so it should be pretty efficient. – gnovice Aug 28 '17 at 16:01
1

Depending on the format of your real data, and if you can find strings that contain your string:

any( ~cellfun('isempty',strfind( arrayfun( @(x)[x.ad.treasurehunt],s,'uni',0 ) ,str)) )