How can I find multiple strings in a cell array?

70 vues (au cours des 30 derniers jours)
Paul Fishback
Paul Fishback le 6 Avr 2016
Commenté : Dooyoung Kim le 2 Août 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.

Réponse acceptée

Adam
Adam le 6 Avr 2016
Try:
Match=cellfun(@(x) ismember(x, {'A1','A2','A3'}), Channels, 'UniformOutput', 0);
r=find(cell2mat(Match));
  2 commentaires
Paul Fishback
Paul Fishback le 6 Avr 2016
Thanks! Works perfectly.
Guillaume
Guillaume le 6 Avr 2016
And unnecessarily complicated...

Connectez-vous pour commenter.

Plus de réponses (1)

Guillaume
Guillaume le 6 Avr 2016
Modifié(e) : Guillaume le 6 Avr 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 commentaires
Adam
Adam le 6 Avr 2016
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!
Dooyoung Kim
Dooyoung Kim le 2 Août 2018
Thanks. It's simple and works well!

Connectez-vous pour commenter.

Catégories

En savoir plus sur Data Type Conversion dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by