1

My program creates a matrix that the values of the cells in several rows are the same in the corresponding columns. I want to delete some of these rows in order to filter the matrix. To clarify, my matrix has the following form,

A=[ 1 2 3 4
    1 2 3 5
    1 2 3 6
    1 2 3 7
    5 6 7 8
    5 6 7 9
    5 6 7 10]

and I want to delete the rows that in the first, the second and the third column their values are the same and leave in the matrix the rows that in the forth row has the biggest value. The result should be the following matrix:

A=[ 1 2 3 7
    5 6 7 10]

I know that when we delete rows in matrix with a condition we use something like the following: M(M(:,4)<=1.5,:)=[];, which deletes all the rows in the matrix that in the fourth column have values less than 1.5. But I don't know how to do something like I described

vasouli
  • 21
  • 8

3 Answers3

2

The code below does the following steps:

  1. sort A by the last column in descending order
  2. find the unique tuples out of the first 3 columns
  3. based on 2, select the rows which have the highest value in the last column

>> [Y,I]=sort(A(:,4), 'descend');
>> B=A(I,:);
>> [~, ind] = unique(B(:,1:3), 'rows', 'stable');

>> result = B(ind,:)

result =

 5     6     7    10
 1     2     3     7
m.s.
  • 16,063
  • 7
  • 53
  • 88
  • This result is in the reverse order compared to the desired output in the post.... I guess that doesn't really matter because you do handle the case when the input isn't sorted by row. – rayryeng Oct 16 '15 at 14:36
  • Yes, actually it doesn't matter that the output is in the reverse order, because most of the time the input isn't sorted and it needs to be sorted before deleting the rows. Thank you both, by the way! – vasouli Oct 16 '15 at 14:42
  • If that's the case, then my solution will work too. It assumes that the rows are sorted before deletion anyway. – rayryeng Oct 16 '15 at 18:52
1

Another method is to use accumarray which will allow easily you to choose arbitrary functions and not just the maximum value in each group:

[a,~,subs] = unique(A(:,1:3),'rows');
B = [a, accumarray(subs,A(:,4),[],@max)]
Dan
  • 45,079
  • 17
  • 88
  • 157
0

Use unique with the rows flag and index into the first three columns. Make sure you choose last so that you choose the last unique value encountered. The default way is to give you the first unique value encountered.

What you need out of this unique call is the second element, which gives you the rows of the last uniquely encountered rows, then you'd use this to subset into your original matrix:

>> [~,ind,~] = unique(A(:,1:3), 'rows', 'last');
>> B = A(ind,:)

B =

     1     2     3     7
     5     6     7    10
rayryeng
  • 102,964
  • 22
  • 184
  • 193