MATLAB Answers

0

Find the cell index in a nested cell array, corresponding to a string (by using strcmp)

Asked by Simone Loreti on 16 Sep 2019 at 13:00
Latest activity Edited by Bruno Luong
on 16 Sep 2019 at 20:13
I have a 1×2 nested cell array A (cell array within a cell array):
A =
1×2 cell array
{43612×7 cell} {863892×7 cell}
where
A{1} =
{'Up' } {'Down' } {'Left' } {'Right'} {'BLUE'}
{'1' } {'7' } {'1' } {'8' } {'3' }
{'2' } {'7' } {'4' } {'3' } {'7' }
{'9' } {'1' } {'6' } {'2' } {'1' }
{'...' } {'...' } {'...' } {'...' } {'...' }
A{2} =
{'Up' } {'Down' } {'Left' } {'Right'} {'RED' }
{'2' } {'1' } {'1' } {'1' } {'2' }
{'6' } {'1' } {'7' } {'4' } {'2' }
{'5' } {'9' } {'8' } {'4' } {'4' }
{'...' } {'...' } {'...' } {'...' } {'...' }
If possible, by using only 1 or 2 lines of code, I would like to know if the text 'BLUE' is in A{1} or in A{2}.
The full answer would be: 'BLUE' is in A{1}(1,5), but I would like to know just the first index of A, i.e. either A{1} or A{2}.
Therefore, if we consider only the firs index of A, i.e. either A{1} or A{2}, my Result would be something like:
Result = 2x1 logical array
1
0
Which means my 'BLUE' text is in A{1}.
My first attempt started by using 'strcmp' in this way:
cellfun(@(x) strcmp(x, 'BLUE'), A, 'UniformOutput', false)
But then I got stuck... Any suggestion to get what I need in only 1 or 2 lines of code ?
Hope my question is clear enough.... Thanks a lot and best regards!

  0 Comments

Sign in to comment.

4 Answers

Answer by Matt J
on 16 Sep 2019 at 13:07
 Accepted Answer

B=cellfun(@(x) strcmp(x, 'BLUE'), A, 'UniformOutput', false);
cellfun(@(c) any(c(:)), B)

  1 Comment

Edit:
B = cellfun(@(x) strcmp([x{:}], 'BLUE'), A, 'UniformOutput', false);
cellfun(@(c) any(c(:)), B)

Sign in to comment.


Answer by Bruno Luong
on 16 Sep 2019 at 13:23
Edited by Bruno Luong
on 16 Sep 2019 at 15:46

A{1} = { ...
{'Up' } {'Down' } {'Left' } {'Right'} {'BLUE'}
{'1' } {'7' } {'1' } {'8' } {'3' }
{'2' } {'7' } {'4' } {'3' } {'7' }
{'9' } {'1' } {'6' } {'2' } {'1' }
{'...' } {'...' } {'...' } {'...' } {'...' }}
A{2} = {...
{'Up' } {'Down' } {'Left' } {'Right'} {'RED' }
{'2' } {'1' } {'1' } {'1' } {'2' }
{'6' } {'1' } {'7' } {'4' } {'2' }
{'5' } {'9' } {'8' } {'4' } {'4' }
{'...' } {'...' } {'...' } {'...' } {'...' }}
% testfun (ONELINE function)
% EDIT version
% returns 1 x 2 boolean arrays B, B(i) is TRUE if word exists in A{i}
testfun = @(word) ismember([0 1],find(strcmp([A{1}{:} A{2}{:}], word))>numel(A{1}));
testfun('BLUE')
testfun('RED')
testfun('Up')
testfun('YELLOW')
testfun('3')
testfun('5')

  0 Comments

Sign in to comment.


Answer by the cyclist
on 16 Sep 2019 at 13:35
Edited by the cyclist
on 16 Sep 2019 at 13:38

Here is a one-liner:
cellfun(@(y)any(any(cellfun(@(x)isequal(x,{'BLUE'}),y))),A)
I stumbled across this function for dealing with nested cell arrays. I did not try it myself, but it could make this a bit more elegant-looking.

  0 Comments

Sign in to comment.


Answer by Simone Loreti on 16 Sep 2019 at 14:14

Dear All,
Thanks a lot for your help!
I tried all the solutions proposed (so far) by Matt J, Bruno Luong and the cyclist:
clear all; clc;
A{1} = { ...
{'Up' } {'Down' } {'Left' } {'Right'} {'BLUE'}
{'1' } {'7' } {'1' } {'8' } {'3' }
{'2' } {'7' } {'4' } {'3' } {'7' }
{'9' } {'1' } {'6' } {'2' } {'1' }
{'...' } {'...' } {'...' } {'...' } {'...' }};
A{2} = {...
{'Up' } {'Down' } {'Left' } {'Right'} {'RED' }
{'2' } {'1' } {'1' } {'1' } {'2' }
{'6' } {'1' } {'7' } {'4' } {'2' }
{'5' } {'9' } {'8' } {'4' } {'4' }
{'...' } {'...' } {'...' } {'...' } {'...' }};
% Matt J
tic
B = cellfun(@(x) strcmp(x, 'BLUE'), A, 'UniformOutput', false);
cellfun(@(c) any(c(:)), B)
toc
% Bruno Luong
tic
testfun = @(word) unique((find(strcmp([A{1}{:} A{2}{:}], 'BLUE'))>numel(A{1}))+1);
testfun('BLUE')
toc
% the cyclist
tic
cellfun(@(y)any(any(cellfun(@(x)isequal(x,{'BLUE'}),y))),A)
toc
I got as follows:
% Matt J
ans =
1×2 logical array
0 0
Elapsed time is 0.002689 seconds.
% Bruno Luong
ans =
1
Elapsed time is 0.004951 seconds.
% the cyclist
ans =
1×2 logical array
1 0
Elapsed time is 0.002189 seconds.
To me - If I did everything correctly - it looks like that the best answer in terms of elapsed time is that one proposed by the cyclist. Therefore, I would like to accept his/her answer.
I greatly appreciate all your ideas and I thank you all for your efforts and time.
Regards,
SL

  5 Comments

The edited answer by Matt J results in the correct [1 0] logical array for both the small and the large samples... I am gonna accept his answer... Thanks!
Matt edit his code and correct the BUG, now his code runs about the same time as mine.
clear
createfun = @(s) arrayfun(@(x) {sprintf('%d',x)}, ceil(1000*rand(s)), 'unif',0);
A{1}=createfun([43612 7]);
A{2}=createfun([863892 7]);
% Matt J
tic
B = cellfun(@(x) strcmp([x{:}], '123'), A, 'UniformOutput', false);
matt_r = cellfun(@(c) any(c(:)), B);
toc % Elapsed time is 4.430430 seconds.
tic
testfun = @(word) ismember([0 1],find(strcmp([A{1}{:} A{2}{:}], word))>numel(A{1}));
bruno_r = testfun('123');
toc % Elapsed time is 3.967751 seconds.
% the cyclist
tic
cyclist_r = cellfun(@(y)any(any(cellfun(@(x)isequal(x,{'123'}),y))),A);
toc % Elapsed time is 22.860207 seconds.
Edit fix createfun BUG (forget inner {...})
Thanks a lot Bruno! Yes, your solutions are very similar in terms of elapsed time... I could give an ex-aequo "accept answer" to both, but I dont know how to do it...Is that possible ?
Just a curiosity: what do you get as results for "matt_r", "bruno_r" and "cyclist_r" ?
Thanks again for these interesting solutions!

Sign in to comment.