Finding all indices by ismember

后端 未结 5 994
野性不改
野性不改 2021-02-04 11:18

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

相关标签:
5条回答
  • 2021-02-04 11:37

    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.

    0 讨论(0)
  • 2021-02-04 11:48

    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
    
    0 讨论(0)
  • 2021-02-04 11:50

    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
    
    0 讨论(0)
  • 2021-02-04 11:54

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

    0 讨论(0)
  • 2021-02-04 11:55

    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.

    0 讨论(0)
提交回复
热议问题