在矩阵中寻找不同值的行索引

3

给定矩阵 A(n * 2)作为源,以及包含 A 的子集的向量 B,我想要找到元素所在行的索引。

A=[1 2;1 3; 4 5];
B=[1 5];
F=arrayfun(@(x)(find(B(x)==A)),1:numel(B),'UniformOutput',false)

在单元格中输出以下内容根据此帮助页面
[2x1 double]    [6]

这段代码中指示了按列出现的所有元素的索引。但我想要行的索引。也就是说,我想知道元素1出现在第1行和第2行,而元素5只出现在第3行。如果索引是按行排列的,我可以使用ceil(F{x}/2)来获得所需的输出。现在由于行数可变,你有什么建议的解决方案?可能会出现没有完整包含标记"rows"的情况,因此ismember函数无法工作。此外,我想知道指定元素的所有索引。

3个回答

3

方法一

F从当前的线性索引形式转换为行索引,使用mod

rows = cellfun(@(x) mod(x-1,size(A,1))+1, F, 'UniformOutput', false);

你可以将此与你的代码合并为一行。还要注意,你可以直接使用B作为arrayfun的输入,这样可以避免一个索引阶段:
rows = arrayfun(@(x) mod(find(x==A)-1,size(A,1))+1, B(:), 'UniformOutput', false);

工作原理:

代码中给出的F是按列主序排列的线性索引。这意味着索引沿着B的第一列向下运行,然后从第二列顶部重新开始向下运行,以此类推。因此,只需使用模(mod)运算即可获得行号。

方法2

使用bsxfunaccumarray:

t = any(bsxfun(@eq, B(:), reshape(A, 1, size(A,1), size(A,2))), 3); %// occurrence pattern
[ii, jj] = find(t); %// ii indicates an element of B, and jj is row of A where it occurs
rows = accumarray(ii, jj, [], @(x) {x}); %// group results according to ii

工作原理:

假设您的示例中有ABt是2x3矩阵。

t =
     1     1     0
     0     0     1
< p > < em > t < / em > 的第 < em > m < / em > 行在列 < em > n < / em > 处包含 < code > 1 < / code > ,如果 < code > B < / code > 的第 < em > m < / em > 个元素出现在 < code > B < / code > 的第 < em > n < / em > 行。这些值通过 < code > find 转换为行和列形式: < / p >
ii =
     1
     1
     2
jj =
     1
     2
     3

这意味着B的第一个元素出现在A的第1行和第2行;第二个元素出现在B的第3行。

最后,使用accumarrayjj的值根据对应的ii值分组,生成所需的结果。

完美的解决方案。我认为你的第一种方法比其他所有方法都要快,是吗?你能详细解释一下你精确而细致的解决方案吗? - hamideh
你的意思是要解释第二个(bsxfunaccumarray),对吗? - Luis Mendo
我尝试使用关键词链接和其他帮助来解决问题。谢谢并祝福你:) - hamideh
@Divakar:事实上,我正在聚类环境中使用两个cellarray。 cellarrayA包含详细的链接信息和权重信息(每个集群一个单元格),而cellarrayB包含第一行中唯一节点ID和相应权重的行2。因此,我必须找到可以用于遍历cellarrayA并为每个节点添加权重的cellarrayA的行号(我在[link](http://stackoverflow.com/questions/30272692/find-index-of-all-numeric-values-in-a-cell-array)中提出了问题)。使用您建议的答案,我将找到解决方案。 - hamideh
@hamideh 好的,我的意思是想问一下A和B的大小,以便确定这些方法的运行时间。你知道它们的大小吗? - Divakar
显示剩余4条评论

3
使用bsxfunaccumarray的一种方法是 -
%// Create a match of B's in A's with each column of matches representing the
%// rows in A where there is at least one match for each element in B 
matches = squeeze(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))

%// Get the indices values and the corresponding IDs of B
[indices,B_id] = find(matches)
%// Or directly for performance:
%// [indices,B_id] = find(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))

%// Accumulate the indices values using B_id as subscripts
out = accumarray(B_id(:),indices(:),[],@(x) {x})

样例运行 -

>> A
A =
     1     2
     1     3
     4     5
>> B
B =
     1     5
>> celldisp(out) %// To display the output, out
out{1} =
     1
     2
out{2} =
     3

精确而出色...您能否为我解释一下您的解决方案? - hamideh
@hamideh 看看编辑后的评论是否有助于解释? - Divakar
我尝试使用关键词链接和其他帮助来解决问题。谢谢并祝福你:) - hamideh
@Divakar +1,顺便说一句,你确定备选方法输出的是期望的结果吗? - Santhan Salai
@SanthanSalai 你是对的!移除了那个方法。 - Divakar

1

使用 arrayfunismemberfind

[r,c] = arrayfun(@(x) find(ismember(A,x)) , B, 'uni',0);

r给出你所需的结果时,你还可以使用c变量来获取B中每个数字所在的列。

样例输入的结果:

>> celldisp(r)

r{1} =
 1
 2

r{2} = 
 3


>> celldisp(c)

c{1} = 
 1
 1

c{2} =
 2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接