Indexing way to look for specifc cell arrays in a cell array of cell arrays?

Hi! I have a cell array of "ordered-pair" cell arrays of strings, e.g.,
A = { {'aa','bb'}, {'cc','dd'}, {'ee','ff'} };
I'd like an indexing (i.e., not-explicitly-looping) way to return the "outer-most" indices of a single matching ordered-pair, e.g., if
X = {'cc', 'dd'};
then
whereEqual(X,A)
should return
[0 1 0].
Similarly, is there a not-explicitly-looping way to "flatten" A:
flatten(A) => {'aa', 'bb', 'cc', 'dd', 'ee', 'ff'}
Thanks for your help!

6 Comments

You'd better provide an example to make your question effective.
http://www.mathworks.com/matlabcentral/answers/6200-tutorial-how-to-ask-a-question-on-answers-and-get-a-fast-answer
Sorry, Matlab Answers lost all my work when I clicked the submit button (I don't know what happened and the error message it gave me was very generic, but I don't remember what it was) and I was so p.o.-ed that I just moved on; I didn't even know (e.g., never got an email notifying me of Fangjun's reply) that the subject of my Q went through!
Anyway, quick example:
A = { {'aa', 'bb'}, {'xx', 'yy'} }
B = { {'aa', 'bb'}, {'cc', 'dd'} }
"whereMember"(A,B) => [1 0]
(Note: I tried ismember(A,B):
>> A = { {'aa', 'bb'}, {'xx', 'yy'} };
>> B = { {'aa', 'bb'}, {'cc', 'dd'} };
but get:
>> ismember(A,B)
??? Error using ==> cell.ismember at 28
Input must be cell arrays of strings.)
DG
Both problems are in the wish-list already: The message vanishs under some circumstances and there is no notification for comments, just for answers. So you have look for new comments manually. This is not very convenient, but not terrible also: We have to _write_ the comments manually also.
(If you're referring to my question having disappeared) but I didn't try to add my content after the fact as a comment, it was part of the original question.
The two problems already included in the wish-list: 1. The message disappears under some strange circumstances (something with empty lines, editing etc). 2. No notification for new comments.

Sign in to comment.

Answers (3)

A = { {'aa', 'bb'}, {'xx', 'yy'} };
B = { {'aa', 'bb'}, {'cc', 'dd'} };
function R = isMemberC(A, B)
R = false(size(A));
for i = 1:numel(A)
for j = 1:numel(B)
if isequal(A{i}, B{j})
R(i) = true;
break;
end
end
end
And according to your other thread: If a case-insensitive comparison is wanted, change the "if isequal..." line to:
function R = isMemberC(A, B)
R = false(size(A));
for i = 1:numel(A)
sizeA = size(A);
for j = 1:numel(B)
if isequal(sizeA, size(B{j}) && all(strcmpi(A{i}, B[j}))
R(i) = true;
break;
end
end
end

4 Comments

Not to look a gift horse in the mouth, but I could have done (and ultimately did something like) that; I was hoping for a not-explicitly-looping way to do it, e.g., some combination of cellfun with ismember or isequal. Is this the other "problem" that you refer to as already being in the wish-list?
Oh, but in light of the speed results discussed in the other thread, maybe I shouldn't put such a premium on loop-free code: is there a list somewhere of Matlab-provided functions that are actually slower than customized loops performing the same function?
Yes. Why so obsessed with no-loopers? My hair straights up whenever I saw cellfun with anonymous function.
@David: Sometimes the most primitive implementation needs the fewest resources. An important rule is coming from the field of house economics: Never touch an item twice. In the original field, this means, that I put the dishes in the right place, if I hold them in my hands. For the programming it means, that it is efficient to reduce the number of accesses to the data. ISMEMBER involves two sortings and sorting means excessive data access. CELLFUN is a C-Mex function, which has to call MATLAB to perform the evaluation of the function handle for each cell element. And the needed mexCellMATLAB function has a lot of overhead. Therefore the CELLFUN(@isempty) is so much slower than CELLFUN('isempty'), which checks the dimensions inside the Mex function.
I'm using a lot of faster replacements for built-in MATLAB functions. You can look in my FEX submissions for some examples.

Sign in to comment.

You probably need to do it using for-loops.
A = { {'aa', 'bb'}, {'xx', 'yy'} };
B = { {'aa', 'bb'}, {'cc', 'dd'} };
Index=false(size(A));
for k=1:length(A)
for j=1:length(B)
if isequal(A{k},B{j})
Index(k)=true;
break;
end
end
end
R = all(reshape(ismember([A{:}],[B{:}]),[],numel(A)))
OR
R = all(reshape(strcmp([A{:}],[B{:}]),[],numel(A)))
ADD
c = mat2cell(cellfun(@(x)[x{:}],[B';A'],'un',0),[numel(B);numel(A)],1)
R = ismember(c{:})';

4 Comments

I'm not sure, if the elements of A and B have the same number of elements. In addition your method replies TRUE for {{'aa', 'bb'}} and {{'bb','aa'}}. Anotehr result, which is most likely not intented:
A = {{'aa', 'bb'}, {'xx', 'yy'}};
B = {{'aa', 'bb', 'cc', 'dd'}};
==> R = [1, 0], but I'd expect [0,0].
The OP's example is not enough to defined the problem exactly.
@David: Please insert the necessary details to define a unique result.
Hi Jan! You're right, it is obvious.
I gave the answer for the particular case.
You are right in both of your examples, Jan: Andrei's code would provide "undesired" answers. In my particular use case (example below), the cell array elements are to be taken as ordered and of immutable structure.
Example:
A = {{'DBfieldA', 'asc'}, {'DBfieldC', 'des'}}
should match neither {{'des', 'DBfieldC'}} nor {{'asc', 'DBfieldC'}}, and if
B = {{'DBfieldA', 'asc'}, {'DBfieldB', 'asc'}, {'DBfieldC', 'des'}}
then
"whereMember"(B,A) should => [1 0 1]
where as
"whereMember"(B, flatten(A)) should => [0 0 0]
Thanks, Jan, for saving me the trouble of having to check Andrei's soln. (for which I am appreciative, Andrei, don't get me wrong.)
mat2cell(cellfun(@(x)[x{:}],[B';A'],'un',0),[numel(B);numel(A)],1)
ismember(ans{:})

Sign in to comment.

Asked:

on 17 Aug 2011

Community Treasure Hunt

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

Start Hunting!