给定数组(例如行向量)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)
比较都是在每次迭代时运行)。
(其他方法在编写时可能会慢几倍或无效。)
答案 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
的第二个输出来查找B
中A
的元素所在的索引,并使用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