This is what is described in one of the examples for ismember:
Define two vectors with values in common.
A = [5 3 4 2]; B = [2 4 4
This line will return all indices:
F=arrayfun(@(x)(find(A(x)==B)),1:numel(A),'UniformOutput',false)
Or a longer version, which might be easier to read:
F=cell(numel(A),1);
for x=1:numel(A)
F{x}=find(A(x)==B);
end
find(A(x)==B)
checks for all occurrences of A(x)
in B
. This is done for each element of the array, either using a for loop or arrayfun
.
A simple approach is to use bsxfun
to test for equality between each element of A
and B
:
ind = bsxfun(@eq, A(:), B(:).');
list = cellfun(@find, mat2cell(ind, ones(1,numel(A)), numel(B)), 'uni', 0);
The matrix ind
gives the result in logical form (i.e. 0 or 1 values), and list
is a cell array containing the indices:
>> ind
ind =
0 0 0 0 0 0
0 0 0 0 0 0
0 1 1 1 0 0
1 0 0 0 0 0
>> celldisp(list)
list{1} =
[]
list{2} =
[]
list{3} =
2 3 4
list{4} =
1
The solutions of Eitan T. and Daniel R answer your question in total. My solution is a convenient and simpler alternative if you are just interested in the elements which are common in both vectors, but NOT how they are related in means of ismember
, e.g. you just want to filter your data for common elements:
I would use the inversion of the opposite: setxor
A = [5 3 4 2];
B = [2 4 4 4 6 8];
[~,iai,ibi] = setxor(A,B); % elements which are not in common
ia = 1:numel(A);
ib = 1:numel(B);
ia(iai) = []; %indices of elements of B in A
ib(ibi) = []; %indices of elements of A in B
Or just the same thing twice:
[~,iai,ibi] = setxor(A,B);
ia = setxor(1:numel(A),iai);
ib = setxor(1:numel(B),ibi);
returns in both cases the indices of the elements also existing in the respective other vector, so to say an implementation of ~isnotmember
ia =
3 4
ib =
1 2 3 4
You can swap the input arguments to ismember
:
[tf, ia] = ismember(B, A)
For your example, you should get:
tf =
1 1 1 1 0 0
ia =
4 3 3 3 0 0
This allows you to find, say, the indices of all the elements of B
that equal A(3)
simply by doing:
find(ia == 3)
Here's a nifty solution for the general case:
[tf, ia] = ismember(B, A);
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], @(x){x});
Note that the output is a cell array. For your example, you should get:
ib =
[]
[]
[2 3 4]
[ 1]
which means that there are no elements in B
matching A(1)
and A(2)
, A(3)
matches elements B(2)
, B(3)
and B(4)
, and A(4)
equals B(1)
.
The most elegant solutions (i.e. those without using iterations of find
) involve swapping the inputs to ismember
and grouping like indexes with accumarray
, as in Eitan's answer, or vectorizing the find with bsxfun
as in Luis Mendo's answer, IMHO.
However, for those interested in a solution with undocumented functionality, and an admittedly hackish approach, here is another way to do it (i.e. for each element of A
, find the indexes of all corresponding elements in B
). The thinking goes as follows: In a sorted B
, what if you had the first and last indexes of each matching element? It turns out there are two helper functions used by ismember
(if you have R2012b+, I think) that will give you both of these indexes: _ismemberfirst
(a builtin
) and ismembc2
.
For the example data A = [5 3 4 2]; B = [2 4 4 4 6 8];
in the question, here is the implementation:
[Bs,sortInds] = sort(B); % nop for this B, but required in general
firstInds = builtin('_ismemberfirst',A,Bs) % newish version required
firstInds =
0 0 2 1
lastInds = ismembc2(A,Bs)
lastInds =
0 0 4 1
The heavy lifting is now done - We have the first and last indexes in B
for each element in A
without having to do any looping. There is no occurrence of A(1)
or A(2)
(5 or 3) in B
, so those indexes are 0
. The value 4 (A(3)
) occurs at locations 2:4 (i.e. all(B(2:4)==A(3))
). Similarly, A(4)
is found at B(1:1)
.
We are able to ignore sortInds
in the above example since B
is already sorted, but an unsorted B
is handled by simply looking up the locations in the unsorted array. We can quickly do this lookup and package each range of indexes with arrayfun
, keeping in mind that the computationally intensive task of actually finding the indexes is already done:
allInds = arrayfun(@(x,y)sortInds(x:y-(x==0)),firstInds,lastInds,'uni',0)
allInds =
[1x0 double] [1x0 double] [1x3 double] [1]
Each cell has the indexes in B
(if any) of each element of A
. The first two cells are empty arrays, as expected. Looking closer at the third element:
>> allInds{3}
ans =
2 3 4
>> A(3)
ans =
4
>> B(allInds{3})
ans =
4 4 4
Testing operation with unsorted B
:
B(4:5) = B([5 4])
B =
2 4 4 6 4 8
[Bs,sortInds] = sort(B);
firstInds = builtin('_ismemberfirst',A,Bs);
lastInds = ismembc2(A,Bs);
allInds = arrayfun(@(x,y)sortInds(x:y-(x==0)),firstInds,lastInds,'uni',0);
allInds{3} % of A(3) in B
ans =
2 3 5
B(allInds{3})
ans =
4 4 4
Is it worth doing it this way, with a penalty for sort
and two effective ismember
calls? Maybe not, but I think it's an interesting solution. If you have a sorted B
, it's even faster since the two built-in functions assume the second argument (Bs
) is sorted and waste no time with checks. Try and see what works for you.