Asked by Paul Fishback
on 6 Apr 2016

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.

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));

Paul Fishback
on 6 Apr 2016

Thanks! Works perfectly.

Guillaume
on 6 Apr 2016

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'}))

Paul Fishback
on 6 Apr 2016

Thanks--that's much simpler.

Adam
on 6 Apr 2016

Dooyoung Kim
on 2 Aug 2018

Thanks. It's simple and works well!

Sign in to comment.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.