给定两个数组A和B,如何获得最接近A

时间:2016-12-26 14:20:09

标签: arrays matlab sorting

假设我有两个按升序排列的数组,即:

  

A = [1 5 7],B = [1 2 3 6 9 10]

我想从B创建一个新的向量B',它只包含与A值最接近的值(每个值一个)。

我还需要索引。所以,在我的例子中,我想得到:

  

B' = [1 6 9],Idx = [1 4 5]

请注意,第三个值是9.确实6更接近7,但它已经被采取了#9;因为它接近4。

是否有合适的代码?

注意:我的真实数组要大得多,并且包含真实(非int)值

此外,给出B比A

更长

谢谢!

3 个答案:

答案 0 :(得分:0)

假设您希望最小化A元素与B中匹配元素之间的总体差异,问题可以写为分配给每一行的分配问题(A的元素)给定成本矩阵B的列(C的元素)。匈牙利语(或Munkres')算法解决了分配问题。

我假设您希望最小化AB中匹配元素之间的累积平方距离,并使用来自https://www.mathworks.com/matlabcentral/fileexchange/20652-hungarian-algorithm-for-linear-assignment-problems--v2-3-的Yi Cao函数[assignment,cost] = munkres(costMat)

A = [1 5 7];
B = [1 2 3 6 9 10];
[Bprime,matches] = matching(A,B)

function [Bprime,matches] = matching(A,B)
    C = (repmat(A',1,length(B)) - repmat(B,length(A),1)).^2;
    [matches,~] = munkres(C);
    Bprime = B(matches);
end

假设您希望按照问题的建议逐步找到匹配,您可以遍历A,对A中的每个元素找到最近的剩余元素在B中放弃它(sortedmatching以下);或者您可以迭代地形成并丢弃AB中剩余元素之间的距离最小化匹配,直到A中的所有元素都匹配(greedymatching):

A = [1 5 7];
B = [1 2 3 6 9 10];
[~,~,Bprime,matches] = sortedmatching(A,B,[],[])
[~,~,Bprime,matches] = greedymatching(A,B,[],[])

function [A,B,Bprime,matches] = sortedmatching(A,B,Bprime,matches)
    [~,ix] = min((A(1) - B).^2);
    matches = [matches ix];
    Bprime = [Bprime B(ix)];
    A = A(2:end);
    B(ix) = Inf;
    if(not(isempty(A)))
        [A,B,Bprime,matches] = sortedmatching(A,B,Bprime,matches);
    end
end

function [A,B,Bprime,matches] = greedymatching(A,B,Bprime,matches)
    C = (repmat(A',1,length(B)) - repmat(B,length(A),1)).^2;
    [minrows,ixrows] = min(C);
    [~,ixcol] = min(minrows);
    ixrow = ixrows(ixcol);
    matches(ixrow) = ixcol;
    Bprime(ixrow) = B(ixcol);
    A(ixrow) = -Inf;
    B(ixcol) = Inf;
    if(max(A) > -Inf)
        [A,B,Bprime,matches] = greedymatching(A,B,Bprime,matches);
    end
end

虽然在您的示例中产生相同的结果,但这三种方法可能会对相同的数据给出不同的答案。

答案 1 :(得分:0)

通常我会在Matlab中从forwhile循环中尖叫,但在这种情况下我无法看到解决方案是如何被矢量化的。至少它是O(N)(或足够接近,取决于A(i)中每个B的平均匹配数量。在C中编写以下代码并将其编译为mex文件,以使其以最佳速度运行将非常简单,但这是一个纯matlab解决方案:

function [out, ind] = greedy_nearest(A, B)

if nargin < 1, A = [1 5 7]; end
if nargin < 2, B = [1 2 3 6 9 10]; end

ind = A * 0;
walk = 1;
for i = 1:numel(A)
    match = 0;
    lastDelta = inf;
    while walk < numel(B)
        delta = abs(B(walk) - A(i));
        if delta < lastDelta, match = walk; end
        if delta > lastDelta, break, end
        lastDelta = delta;
        walk = walk + 1;
    end
    ind(i) = match;
    walk = match + 1;
end
out = B(ind);

答案 2 :(得分:0)

您可以首先获得A中每个值与B中每个值的绝对距离,对它们进行排序,然后在向下查看每列时获取序列的第一个唯一值。

% Get distance from each value in A to each value in B
[~, minIdx] = sort(abs(bsxfun(@minus, A,B.')));

% Get first unique sequence looking down each column
idx = zeros(size(A));
for iCol = 1:numel(A)
    for iRow = 1:iCol
        if ~ismember(idx, minIdx(iRow,iCol))
            idx(iCol) = minIdx(iRow,iCol);
            break
        end
    end
end

idx应用于B

时的结果
>> idx
1     4     5
>> B(idx)
1     6     9