查找两个数组之间的(多集)差异

时间:2018-08-13 19:51:36

标签: arrays matlab multiset

给定数组(例如行向量)A和B,我如何找到数组C,使B和C合并将得到A?

例如,给定

A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];

然后

C = multiset_diff(A, B) % Should be [4, 6, 4, 3, 1, 5]

(此处的结果顺序无关紧要)。

对于相同的A,如果为B = [2, 4, 5],则结果应为[6, 4, 3, 3, 1, 5, 5]

(由于A中有两个4,而B中有一个4,结果C中应该有2-1 = 1 4。对于其他值,情况类似。 )

PS:请注意,setdiff将删除2、3和5的所有实例,而在这里,无论它们在B中出现多少次,都需要删除它们。


性能:我在本地运行了一些快速n基准测试,以下是供以后参考的结果:

  • @heigele的嵌套循环方法对于小长度的A(例如,最多N = 50个元素)表现最佳。与下一个最佳方法相比,小型(N = 20)A的性能要好3倍,中等大小(N = 50)A的性能要好1.5倍,即:

  • @obchardon的基于histc的方法。当A的大小N开始大于100时,这是表现最好的一种。例如,当N = 200时,这比上述嵌套循环方法好3倍。

@matt的for + find方法的效果与小N的histc方法相当,但是对于大N的性能却迅速下降(这是有道理的,因为整个C == B(x)比较都是在每次迭代时运行)。

(其他方法在编写时可能会慢几倍或无效。)

5 个答案:

答案 0 :(得分:4)

我不喜欢循环,但是对于A的随机扰动,这是我想到的最好的方法。

C = A;
for x = 1:numel(B)
C(find(C == B(x), 1, 'first')) = [];
end

我很想知道A的不同顺序对解决方案方法的影响,因此我设置了这样的测试:

Ctruth = [1 3 3 4 5 5 6];
for testNumber = 1:100
    Atest = A(randperm(numel(A)));
    C = myFunction(Atest,B);
    C = sort(C);
    assert(all(C==Ctruth));
end

答案 1 :(得分:4)

这是向量化的方式。内存不足,主要是为了娱乐:

tA = sum(triu(bsxfun(@eq, A, A.')), 1);
tB = sum(triu(bsxfun(@eq, B, B.')), 1);
result = setdiff([A; tA].', [B; tB].', 'rows', 'stable');
result = result(:,1).';

这个想法是通过为每个条目添加一个出现编号来使其唯一。向量变为2列矩阵,setdiff'rows'选项一起应用,然后从结果中删除标记。

答案 2 :(得分:3)

您可以使用ismember的第二个输出来查找BA的元素所在的索引,并使用diff删除重复项:

此答案假定B已排序。如果不是这种情况,则必须在执行上述解决方案之前对B进行排序。

第一个示例:

A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];
%B = sort(B); Sort if B is not sorted.
[~,col] = ismember(B,A);
indx = find(diff(col)==0);
col(indx+1) = col(indx)+1;
A(col) = [];
C = A;

>>C

4     6     4     3     1     5

对于第二个示例:

A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 4, 5, 5];
%B = sort(B); Sort if B is not sorted.
[~,col] = ismember(B,A);
indx = find(diff(col)==0);
col(indx+1) = col(indx)+1;
A(col) = [];
C = A;
>>C

6     4     3     3     1     5

答案 3 :(得分:3)

还是使用histc函数的另一种方法:

A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];

uA  = unique(A);
hca = histc(A,uA); 
hcb = histc(B,uA);
res = repelem(uA,hca-hcb)

我们只需根据向量A的唯一值来计算每个向量的重复元素数,然后使用repelem来创建结果。

此解决方案不保留初始顺序,但对您来说似乎不是问题。

我使用histc获得八度兼容性,但是不建议使用此功能,因此您也可以使用histcounts

答案 4 :(得分:3)

受Matt的强烈启发,但在我的机器上速度提高了40%:

function A = multiDiff(A,B)
for j = 1:numel(B)
    for i = 1:numel(A)
        if A(i) == B(j)
            A(i) = [];
            break;
        end
    end
end
end