Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing an array with every row in a matrix (which may differ in column count)

Say I have a 7*3 matrix t.

>> t=[2,1,3;5,1,9;4,6,1;1,4,6;7,1,5;1,7,4;9,7,5]

t =

 2     1     3
 5     1     9
 4     6     1
 1     4     6
 7     1     5
 1     7     4
 9     7     5

and an array with two values like this

e=[2,1]

e =

 2     1

I need to know which row in t has the values 1 and 2 in it( ie, the values of matrix e). ie, given a function match(e,t), it should return the row number which satisfies this.

I've written a function match, and it does the job.

function [ faceindex ] = match(e,t)
c=ismember(t,e)
d=sum(c,2)
faceindex=find(d==2) 
end

And this is how it works :

match(e,t)

c =

 1     1     0
 0     1     0
 0     0     1
 1     0     0
 0     1     0
 1     0     0
 0     0     0

d =

 2
 1
 1
 1
 1
 1
 0

faceindex =

 1

ans =

 1

However, I use it for a rather large input, and it's called a number of times and it takes a while to run. Matlab's profiler shows me the problem is with this ismember function. Is there any way of doing the matching in a faster way? I'm open to any kinds of solutions or hints. Maybe something that doesn't have to use ismember to do the checking. Please note that the order doesn't matter. If e is 2,1...the row should have 1 and 2 and can be in any order.

like image 464
Tina Maria Avatar asked May 26 '14 06:05

Tina Maria


2 Answers

You said that you need to identify the rows in t that have the values 1 and 2 in it ( i.e., the values of matrix e) and you have used the code - faceindex=find(d==2),so I am assuming if e is say [1 2 7], we must look to find rows in t in which the count of the number of times elements of e appear in any order must be equal to 3(= number of elements in e) and thus we must try to replicate something like - faceindex=find(d==3). I am also assuming that the values in e are unique values.

With these set of conditions to be used, you can try this bsxfun approach for a general case with e and t -

mat1 = bsxfun(@eq,t,permute(e,[3 1 2]));
faceindex = find(sum(reshape(mat1,size(t,1),[]),2)==numel(e));

If I focus only at your words and not at your code, let me quote an important portion of your text - "I need to know which row in t has the values 1 and 2 in it". From these words, it could be inferred that you just want to find out the row numbers of t, where each of the elements in e appear at least once. So following this new assumption and that the values in e are unique values, you can try a slightly modified version of my earlier code -

mat1 = bsxfun(@eq,t,permute(e,[3 1 2]));
faceindex = find(all(squeeze(any(mat1,2)),2));

So, please make sure what you are really going for, because I don't see your code speaking up for your text.

Edit 1: In one of your comments, you said it's always just two values in e and that t will never have repeating values, so for such a specific case, two approaches can be used.

Approach 1:

faceindex = find(sum( (t==e(1) | t==e(2)),2 )==2,1);

Approach 2 (better for very large datasizes):

ind1 = find(any(t==e(1),2));
[r,c] = find(t(ind1,:)==e(2),1);
faceindex = ind1(r);
like image 70
Divakar Avatar answered Oct 06 '22 00:10

Divakar


Hey not sure if its faster but, this would do the trick:

A = round(rand(10,4)*5)
B =zeros(size(A));
B(or(A==1,A==2)) = 1

Here A is the matrix in this case ranges from 0 to 5. B is the result and B(i,j) is 1 for A(i,j) is equal to 1 or 2. You can play around with the arguments in B. And you have to add your other variables d and faceindex.

like image 20
The Minion Avatar answered Oct 05 '22 22:10

The Minion