4
votes

I have three vectors in Matlab that are possibly of different sizes. I want to compare the values in each vector against all the other values in the other vectors and only keep values that are 'close' in 2 out of 3 of the vectors. And by 'keep', I mean take the average of the close values.

For example:

a = [10+8i, 20];
b = [10+9i, 30, 40+3i, 55];
c = [10, 60, 41+3i];

If I set a closeness tolerance such that only values that are within, say, a magnitude of 1.5 of each other are kept, then the following values should be marked as close:

  • 10 + 8i and 10 + 9i
  • 40 + 3i and 41 + 3i

Then the routine should return a vector of length that contains the average of each of these sets of numbers:

finalVec = [10+8.5i,40.5+3i];

What is the most efficient way to do this in Matlab? Is there a better way than just straightforward looping over all elements?

2
I suggest you first do it with loops and then think about vectorizing, as this is not an obviously straightforward vectorizable option. "early optimization is the root of all evil" - Ander Biguri

2 Answers

4
votes

Building on this solution:

a = [10+8i, 20];
b = [10+9i, 30, 40+3i, 55];
c = [10, 60, 41+3i];

M1 = compare_vectors(a , b);
M2 = compare_vectors(a , c);
M3 = compare_vectors(b , c);
finalVec = [M1, M2 , M3]


function M = compare_vectors(a , b)

    % All combinations of vectors elements
    [A,B] = meshgrid(a,b);
    C = cat(2,A',B');
    D = reshape(C,[],2);

    % Find differences lower than tolerance
    tolerance = 1.5
    below_tolerance = abs(D(:,1) - D(:,2)) < tolerance ;

    % If none, return empty
    if all(below_tolerance== 0)
        M = [];
        return
    end

    % Calculate average of returned values
    M = mean(D(below_tolerance,:));

end
2
votes
% your data   
a = [10+8i, 20];
b = [10+9i, 30, 40+3i, 55];
c = [10, 60, 41+3i];
tol = 1.5;

% call the function with each combination of vectors and concatenate the results
finalVec = cell2mat(cellfun(@closepoints, {a, a, b}, {b, c, c}, {tol, tol, tol}, 'Uni', 0))

function p = closepoints(a, b, tol)
    % find the pairs of indexes of close points 
    %    the bsxfun() part calculates the distance between all combinations of elements of the two vectors
    [ii,jj] = find(abs(bsxfun(@minus, a, b.')) < tol);
    % calculate the mean
    p = (a(jj) + b(ii))/2;
end

Note that cellfun() isn't really faster than calling the function multiple times in a row or using a for loop. But it would be easier to add more vectors than the former and is IMO nicer to look at than the latter.