MATLAB Answers

1

How can I find multiple strings in a cell array?

Asked by Paul Fishback on 6 Apr 2016
Latest activity Commented on by Dooyoung Kim on 2 Aug 2018
I have a cell array of strings, called Channels, each containing an EEG channel label, e.g. 'A1', 'A2', ....,
I'd like to find indices that correspond to a subset of the strings. For a single string, I've found the following works:
Match=cellfun(@(x) strcmp({'A3'}, x), Channels, 'UniformOutput', 0);r=find(cell2mat(Match))
The value of r is 3, which is what I would expect. However, if I try to find indices that match more than one channel, I obtain an answer I cannot interpret. For example,
Match=cellfun(@(x) strcmp({'A1','A2','A3'}, x), Channels, 'UniformOutput', 0);r=find(cell2mat(Match))
r=1, 5, 9, which is incorrect. The values should be 1, 2, 3.

  0 Comments

Sign in to comment.

2 Answers

Answer by Adam
on 6 Apr 2016
 Accepted Answer

Try:
Match=cellfun(@(x) ismember(x, {'A1','A2','A3'}), Channels, 'UniformOutput', 0);
r=find(cell2mat(Match));

  2 Comments

Thanks! Works perfectly.
And unnecessarily complicated...

Sign in to comment.


Answer by Guillaume
on 6 Apr 2016
Edited by Guillaume
on 6 Apr 2016

First, your first solution is unnecessarily complicated. You're basically using a loop ( cellfun) to compare each individual string with 'A3'. When you're comparing individual strings with each others, strcmp returns a scalar, so you don't need to have 'UniformOutput', false in your cellfun call. As a result, your Match would be a matrix and you wouldn't need the subsequent cell2mat either. But in any case, you don't even need the loop since strcmp is happy to directly compare a string with a cell array. So your first example could simply be:
r = find(strcmp('A3', Channels))
Now, in your second case, if you still were to use strcmp for the comparison, you would indeed need cellfun (or an explicit loop) to break your Channels cell array into individual strings as you can't strcmp two cell arrays together (expect if they're the same size but then it's a different behaviour). When you do
strcmp({'A1', 'A2', 'A3'}, x)
the output is a vector with 3 elements of either 0s or 1s, telling you respectively whether 'A1', 'A2', 'A3' matches x. So for example if x is 'A2', you get as output [0 1 0]. Therefore assuming your Channels is the {'A1'; 'A2'; 'A3'}, the output of your cellfun is:
{[1 0 0]; %first string of {'A1', 'A2', 'A3'} matches x (first string of Channels)
[0 1 0]; %second string of {'A1', 'A2', 'A3'} matches x (second string of Channels)
[0 0 1]} %third string of {'A1', 'A2', 'A3'} matches x (third string of Channels)
The cell2mat call then convert that into a matrix that happens to be the identity matrix, and find on that indeed returns [1, 5, 9].
The problem with the above is that you don't want a vector for each x, you just want one value that tells you whether or not any of 'A1', 'A2', 'A3' matches x. So you could change the cellfun to:
Match = cellfun(@(x) any(strcmp({'A1', 'A2', 'A3'}, x, Channels); r = find(Match);
Note that again you don't need the 'UniformOutput', false and the cell2mat call since the output of cellfun is now scalar.
However, what you're now doing is testing the membership of one set into another. There is a function for that in matlab: ismember. So the simplest way to do your second comparison is simply with:
r = find(ismember(Channels, {'A1', 'A2', 'A3'}))

  3 Comments

Thanks--that's much simpler.
Yes, that is true. I didn't look too closely at the details, I just substituted your strcmp for an ismember, tested it and left everything else as it was!
Thanks. It's simple and works well!

Sign in to comment.