# How can I find multiple strings in a cell array?

247 views (last 30 days)
Paul Fishback on 6 Apr 2016
Commented: 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.

Try:
Match=cellfun(@(x) ismember(x, {'A1','A2','A3'}), Channels, 'UniformOutput', 0);
r=find(cell2mat(Match));
##### 2 CommentsShowHide 1 older comment
Guillaume on 6 Apr 2016
And unnecessarily complicated...

Guillaume on 6 Apr 2016
Edited: 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'}))
Dooyoung Kim on 2 Aug 2018
Thanks. It's simple and works well!