据我了解,您希望提取矩阵的行,其中它们在第一列和第三列中都共享共同值。您当然可以使用arrayfun 方法,但您需要修改调用unique 的方式。具体来说,在您要检查的列上使用 'rows' 标志,然后在您的 arrayfun 调用中,使用 bsxfun 结合 all 来检查那些包含您想要的列元素的每个唯一组合的行,所以:
>> M=[ 1 3 5 6; 3 6 5 4; 1 8 5 1; 4 6 5 7; 3 6 4 5; 3 6 4 4];
>> r = unique(M(:,[1 3]), 'rows', 'stable');
>> A = arrayfun(@(x) M(all(bsxfun(@eq, M(:,[1 3]), r(x,:)),2), :), 1:size(r,1),'uni', 0);
>> celldisp(A);
A{1} =
1 3 5 6
1 8 5 1
A{2} =
3 6 5 4
A{3} =
4 6 5 7
A{4} =
3 6 4 5
3 6 4 4
请务必注意,我使用'stable' 标志,因为unique 默认情况下排序唯一条目。 'stable' 确保我们按照遇到它们的顺序 找到唯一条目,就像在您的问题中看到的所需输出一样。顺便说一句,'uni' 是 'UniformOutput' 的缩写。从长远来看,它会帮你省去打字的麻烦:)。
第三行很拗口,但很容易解释。首先,看一下这句话:
bsxfun(@eq, M(:,[1 3]), r(x,:))
我们在这里要做的是获取r 的每一行,这是取自M 的第1 列和第3 列的值的唯一配对,并查看M 的一行中的每个值是否相等从r 到相应的位置。为了找到匹配项,我们需要确保此结果的一行中的 所有 值都等于 1,这就是为什么我们需要在这里使用 all 并查看列:
all(bsxfun(@eq, M(:,[1 3]), r(x,:)),2)
一旦我们找到与r 中的特定行匹配的这些行,我们就会使用这些行并索引到我们的矩阵M 并提取满足r 中的行的行,我们在M 中寻找因此:
M(all(bsxfun(@eq, M(:,[1 3]), r(x,:)),2), :)
x 从 1 迭代到 r 中的行数,并且在每次迭代中,我们每次都从 r 中提取一个唯一行。最终结果将是一个元胞数组,它根据第一列和第三列之间的共同元素对 M 的行进行分组。
如果您希望这样做更有效率,您可以按照 Divakar 的建议进行操作,只使用 unique 的第三个输出。这也会使事情更容易阅读:
>> M=[ 1 3 5 6; 3 6 5 4; 1 8 5 1; 4 6 5 7; 3 6 4 5; 3 6 4 4];
>> [~,~,r] = unique(M(:,[1 3]), 'rows', 'stable');
>> A = arrayfun(@(x) M(r == x, :), 1:max(r),'uni', 0);
>> celldisp(A);
A{1} =
1 3 5 6
1 8 5 1
A{2} =
3 6 5 4
A{3} =
4 6 5 7
A{4} =
3 6 4 5
3 6 4 4
当然更具可读性!现在发生的情况是,unique 的第三个输出分配了一个唯一 ID,从 1 到您拥有的作为unique 输入的唯一值。然后,我们只需找到最大 ID,并从 1 迭代到最大 ID,在每次迭代中,此索引用作从矩阵中提取对应于第一列和第三列的每个唯一组合的行的一种方式M.