How to filter a matrix Row by Row to get the highest value?

1 view (last 30 days)
Dear all,
I have this matrix
A= [ 31,62.3, 31,96.3, 31,52.8, 57,91.4 ;...
71,64.4, 31,93.5, 31,36.2, 57,83.1 ] ;
I want to scan this matrix row by row such that values at the odd columns will not be repeated + it will get the highest value at the even column attached to it
So I want the following answer:
Answer = [ 31,96.3 57,91.4 0,0 ;...
71,64.4 31,93.5 57,83.1 ]
The oreder of pairs in each row is not important. The following answe is also OK
Answer = [ 57,91.4 31,96.3 0,0 ;...
31,93.5 57,83.1 71,64.4 ]
Many thanks in advance.
  4 Comments
Image Analyst
Image Analyst on 26 Mar 2019
It's such a quirky thing to do that you may have to end up just writing a custom program from low level functions like for loops and max(). I don't think there is a built in function to do exactly this thing. But there are a lot of ways it could be done from low level functions.
Why do you need to do this unusual thing anyway - what's the use case?
By the way, "raw" means "uncooked food", and a line of an array is "row", not "raw".
Ghost
Ghost on 26 Mar 2019
Thank you Image Analyst. I corrected the spelling.
I just needed this for one idea that I am trying to solve. I don't think it has many applications.

Sign in to comment.

Accepted Answer

madhan ravi
madhan ravi on 26 Mar 2019
See if this satisfies your needs:
C = zeros(size(A));
for k = 1:size(A,1)
B = reshape(A(k,:),2,[]).';
G = findgroups(B(:,1));
BB = reshape(B(any(B(:,2)==splitapply(@(x)max(x),...
B(:,2),G).',2),:).',1,[]);
C(k,1:numel(BB)) = BB;
end
C(:,all(C==0,1)) = []
Note: Not tested under all circumstances.

More Answers (1)

Guillaume
Guillaume on 26 Mar 2019
A version with no loop, but a few accumarray so may not be faster:
%build demo data
A = [31,62.3, 31,96.3, 31,52.8, 57,91.4 ;...
71,64.4, 31,93.5, 31,36.2, 57,83.1 ];
A = [A; A]; A(4, 5) = 32
%algorithm
workingA = [repelem((1:size(A, 1))', size(A, 2)/2), reshape(A.', 2, []).']; %reshape in 2 columns of pairs and prepend with a column indicating which row the data came from
[urows, ~, id] = unique(workingA(:, [ 1 2]), 'rows'); %identify unique 1st pair element per row
offsets = accumarray(workingA(:, 1), id, [], @max); %need to reset id for each row, so find max id per row
offsets = [0;offsets(1:end-1)];
column = (id - offsets(workingA(:, 1)))*2; %and subtract max of previous row from each row
result = accumarray([urows(id, 1), column], workingA(:, 3), [], @max); %distribute max for each unique pair and row
result = result + [accumarray([urows(id, 1), column-1], workingA(:, 2), [], @(v) v(1)), zeros(size(result, 1), 1)] %add 1st element of each pair
With a loop, a cleaner (in my opinion) version of Madhan's answer:
result = zeros(size(A));
for row = 1:size(A, 1)
[uvals, ~, id] = unique(A(row, 1:2:end));
result(row, 2:2:end) = accumarray(id, A(row, 2:2:end), [size(A, 2)/2, 1], @max);
result(row, 1:2:numel(uvals)*2) = uvals;
end
result(:, all(result == 0, 1)) = []

Products


Release

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!