没有重复的行 - MATLAB

Rows without repetitions - MATLAB

我有一个 matrix (4096x4) 包含从 8 个数字池中取出的四个值的所有可能组合。

...
3    63    39     3
3    63    39    19
3    63    39    23
3    63    39    39
...

我只对包含四个唯一值的矩阵行感兴趣。例如,在上面的部分中,第一行和最后一行应该被删除,给我们 -

...
3    63    39    19
3    63    39    23
...

我当前的解决方案感觉不够优雅——基本上,我遍历每一行并将其添加到 result 矩阵(如果它包含四个唯一值):

result = [];
for row = 1:size(matrix,1)
    if length(unique(matrix(row,:)))==4
        result =  cat(1,result,matrix(row,:));
    end
end

有没有更好的方法?

方法 #1

基于

diff and sort 的方法必须非常有效 -

sortedmatrix = sort(matrix,2)
result = matrix(all(diff(sortedmatrix,[],2)~=0,2),:)

将其分解为几个步骤进行解释

  1. 按列排序,使每行中的重复值彼此相邻。我们用 sort 来完成这个任务。
  2. 查找连续元素之间的差异,这将在排序后捕获那些重复的元素。 diff 是用于此目的的工具。
  3. 对于带有 at least one zero 的任何行表示具有重复行的行。换句话说,任何带有 no zero 的行都表示没有重复行,我们希望在输出中包含这些行。 all 我们在这里完成了工作,以获得此类匹配项的逻辑数组。
  4. 最后,我们使用 matrix indexing 到 select 来自 matrix 的那些行以获得预期的输出。

方法 #2

这可能是一种基于实验性 bsxfun 的方法,因为它不会节省内存 -

matches = bsxfun(@eq,matrix,permute(matrix,[1 3 2]))
result = matrix(all(all(sum(matches,2)==1,2),3),:)

将其分解为几个步骤进行解释

  1. bsxfun.
  2. 的同一行中找到每个元素与所有其他元素匹配的逻辑数组
  3. 通过将 dim-2 个匹配项中的匹配项相加,然后在 dim-2dim-3 中找到 all ones 个元素来寻找“非口是心非”,从而获得相同的索引数组与我们之前基于 diff + sort 的方法一样。
  4. 使用二进制索引数组 select 来自 matrix 的适当行作为最终输出。

方法 #3

从 MATLAB File-exchange 的 post combinator 获得帮助 并假设您在名为 pool8 的数组中有 8 值池,您可以像这样直接获得 result -

result = pool8(combinator(8,4,'p'))

combinator(8,4,'p') 基本上让我们立即获得 8 元素的索引 4 并且没有重复。我们使用这些索引索引到 pool 并获得预期的输出。

对于有限数量的池,这将起作用。创建一个唯一数组,遍历池中的每个数字,计算它在行中出现的次数,如果找到一个或零个数字,则只将 IsUnique 保持为 1。接下来,找到 IsUnique 仍然是 1 的位置,提取这些行,我们就完成了。

matrix = [3,63,39,3;3,63,39,19;3,63,39,23;3,63,39,39;3,63,39,39;3,63,39,39];
    IsUnique = ones(size(matrix,1),1);
    pool = [3,63,39,19,23,6,7,8];
    for NumberInPool = 1:8    
        Temp = sum((matrix == pool(NumberInPool))')';
        IsUnique = IsUnique .* (Temp<2);
    end
    UniquePositions = find(IsUnique==1);
    result = matrix(UniquePositions,:)