通过ismember查找所有指数

时间:2013-12-08 11:27:29

标签: matlab

这是ismember的一个示例中描述的内容:

  

定义两个具有共同值的向量。

     

A = [5 3 4 2]; B = [2 4 4 4 6 8];

     

确定AB的哪些元素以及B中的相应位置。

     

[Lia,Locb] = ismember(A,B)

结果是:

Lia =
     0     0     1     1

Locb =    
     0     0     2     1

B中与A(3)匹配的索引最低的元素为B(2)A(4)等于B(1)。有没有办法找到所有B中相同元素匹配的A元素的索引?

5 个答案:

答案 0 :(得分:5)

您可以将输入参数交换为ismember

[tf, ia] = ismember(B, A)

对于你的例子,你应该得到:

tf =
     1     1     1     1     0     0

ia = 
     4     3     3     3     0     0

这样,您就可以通过以下方式找到B等于A(3)的所有元素的索引:

find(ia == 3)

这是一般案例的一个很好的解决方案:

[tf, ia] = ismember(B, A);
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], @(x){x});

请注意,输出为cell array。对于你的例子,你应该得到:

ib = 
    []
    []
    [2     3     4]
    [      1]

表示B匹配A(1)A(2)A(3)匹配元素B(2)B(3)和{{ 1}},B(4)等于A(4)

答案 1 :(得分:3)

此行将返回所有索引:

F=arrayfun(@(x)(find(A(x)==B)),1:numel(A),'UniformOutput',false)

或更长版本,可能更容易阅读:

F=cell(numel(A),1);
for x=1:numel(A)
  F{x}=find(A(x)==B);
end

find(A(x)==B)检查A(x)B的所有出现次数。这是针对数组的每个元素完成的,使用for循环或arrayfun

答案 2 :(得分:2)

一种简单的方法是使用bsxfun来测试AB的每个元素之间的相等性:

ind = bsxfun(@eq, A(:), B(:).');
list = cellfun(@find, mat2cell(ind, ones(1,numel(A)), numel(B)), 'uni', 0);

矩阵ind以逻辑形式给出结果(即0或1个值),list是包含索引的单元格数组:

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

答案 3 :(得分:2)

最优雅的解决方案(即那些没有使用find迭代的解决方案)涉及将输入交换到ismember并使用accumarray对索引进行分组,如Eitan的答案,或者将查找矢量化与路易斯·门多的答案中的bsxfun一致,恕我直言。

但是,对于那些对具有未记录功能的解决方案感兴趣的人,以及一种公认的hackish方法,这是另一种方法(即对于A的每个元素,找到{{{}}中所有相应元素的索引。 1}})。思路如下:在排序B中,如果您拥有每个匹配元素的第一个最后一个索引,该怎么办?事实证明,B使用了两个辅助函数(如果你有R2012b +,我认为)将为你提供这两个索引:ismember(a _ismemberfirst)和{{1 }}

对于问题中的示例数据builtin,这里是实现:

ismembc2

现在已经完成了繁重的工作 - 我们在A = [5 3 4 2]; B = [2 4 4 4 6 8];中的第一个最后一个索引用于 [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 中的每个元素,而无需执行任何循环。 B中没有AA(1)(5或3),因此这些索引为A(2)。值4(B)出现在位置2:4(即0)。同样,A(3)位于all(B(2:4)==A(3))

我们可以忽略上面示例中的A(4),因为B(1:1)已经排序,但是通过简单地查找未排序数组中的位置来处理未排序的sortInds。我们可以快速执行此查找并使用B打包每个索引范围,请记住,实际查找索引的计算密集型任务已经完成:

B

每个单元格都有arrayfun的每个元素allInds = arrayfun(@(x,y)sortInds(x:y-(x==0)),firstInds,lastInds,'uni',0) allInds = [1x0 double] [1x0 double] [1x3 double] [1] (如果有)的索引。正如预期的那样,前两个单元格是空数组。仔细观察第三个要素:

B

使用未排序的A测试操作:

>> allInds{3}
ans =
     2     3     4
>> A(3)
ans =
     4
>> B(allInds{3})
ans =
     4     4     4

这样做是否值得,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 来电会受到惩罚?也许不是,但我认为这是一个有趣的解决方案。如果你有一个已排序的sort,它会更快,因为两个内置函数假定第二个参数(ismember)已经排序,并且没有时间检查。试着看看哪些对你有用。

答案 4 :(得分:0)

Eitan T.和Daniel R的解决方案总共回答了你的问题。如果您只对两个向量中常见的元素感兴趣,而不是它们如何与ismember的方式相关,例如,我的解决方案是一种方便和简单的替代方案。您只想过滤常见元素的数据:

我会使用相反的反转: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

或两次同样的事情:

[~,iai,ibi] = setxor(A,B);
ia = setxor(1:numel(A),iai);
ib = setxor(1:numel(B),ibi);

在两种情况下都返回元素的索引也存在于相应的其他向量中,所以说 ~isnotmember 的实现

ia =

     3     4

ib =

     1     2     3     4