这是ismember
的一个示例中描述的内容:
定义两个具有共同值的向量。
A = [5 3 4 2]; B = [2 4 4 4 6 8];
确定
A
中B
的哪些元素以及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
元素的索引?
答案 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
来测试A
和B
的每个元素之间的相等性:
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
中没有A
或A(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