Fantastic Mr Fox
Fantastic Mr Fox

Reputation: 33944

Find indices of elements in an array based on a search from another array

Imagine that i have two arrays:

a = [1, 2, 5, 7, 6, 9, 8, 3, 4, 7, 0];

b = [5, 9, 6];

I want to find the indices of the values of b in a (only the first hit) ie:

c = [3, 6, 5];

Is there an easy Matlab native way to do this without looping and searching.

I have tried to use find() with:

find(a == b)

and it would work if you did this:

for i = 1:length(b)
    index = find(a == b(i));
    c = [c, index(1)]
end

But it would be ideal for it to be easier then this.

Upvotes: 28

Views: 88622

Answers (8)

Gunther Struyf
Gunther Struyf

Reputation: 11168

You can compact your for loop easily with arrayfun into a simple one-liner:

arrayfun(@(x) find(a == x,1,'first'), b )

also see Scenia's answer for newer matlab versions (>R2012b).

Upvotes: 20

Luis Mendo
Luis Mendo

Reputation: 112759

Similar to @tmpearce's answer, but possibly faster:

[valid, result] = max(bsxfun(@eq, a(:), b(:).')); %'// max finds first occurrence
result = result(valid); %// this is necessary in case some value of b is not in a

Upvotes: 1

scenia
scenia

Reputation: 1629

This is actually built into ismember. You just need to set the right flag, then it's a one liner and you don't need arrayfun. Versions newer than R2012b use this behavior by default.

Originally, ismember would return the last occurence if there are several, the R2012a flag makes it return the first one.

Here's my testing results:

a = [1, 2, 5, 7, 6, 9, 8, 3, 4, 7, 0, 6];
b = [5, 9, 6];

[~,c] = ismember(b,a,'R2012a');
>> c
c =
     3     6     5

Upvotes: 19

twerdster
twerdster

Reputation: 5027

You could try this:

[c,ind_a] = intersect(a,b)

Upvotes: 4

glarson
glarson

Reputation: 11

a = [1, 2, 5, 7, 6, 9, 8, 3, 4, 7, 0];
b = [5, 9, 6];
c = dsearchn(a',b');

Matlab requires a and b need to be column vectors, hence the transpose.

Upvotes: 1

Amro
Amro

Reputation: 124563

This is a fix to the ismember approach that @Pursuit suggested. This way it handles multiple occurrences of one of the numbers, and returns the result in the correct order:

[tf,loc] = ismember(a,b);
tf = find(tf);
[~,idx] = unique(loc(tf), 'first');
c = tf(idx);

The result:

>> c
c =
     3     6     5

Upvotes: 5

Pursuit
Pursuit

Reputation: 12345

Have you tried ismember?

c_logical_mask = ismember(a, b);

or

c_indexes = find(ismember(a, b));

Upvotes: 1

tmpearce
tmpearce

Reputation: 12693

a = [1, 2, 5, 7, 6, 9, 8, 3, 4, 7, 0, 6];
b = [5, 9, 6];
[r c]=find(bsxfun(@eq,a,b')');
[~,ia,~]=unique(c,'first');
>> r(ia)

ans =

     3
     6
     5

Note: I added an extra 6 at the end of a to demonstrate finding only the first occurrence of each value.

Upvotes: 4

Related Questions