28

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.

3

8 Answers 8

20

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

Sign up to request clarification or add additional context in comments.

2 Comments

arrayfun is no faster than for-loops
@niceman I never said it was... And I believe in some situations it wíll be just as fast or faster when the JIT kicks in (especially on multicore setups). On the other side, some people just like the oneliner-capability of arrayfun. For this question it actually doesn't even matter, as you're better of using Scenia's answer
19

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

Comments

5

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

Comments

4
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.

Comments

4

You could try this:

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

Comments

1

Have you tried ismember?

c_logical_mask = ismember(a, b);

or

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

2 Comments

A couple of things: This doesn't find only the first occurrence of each value of b in a, and it doesn't leave the indices in the right order either.
@tmpearce: I posted a fix of this
1
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.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.