Felix
Felix

Reputation: 2678

Find last true element of columns

I'd like to extract one value per column of a matrix using a condition. Multiple values on each column match that condition, but only the last one should be selected. It is safe to assume that each row contains at least one such value.

So given an NxM matrix and an equally-sized boolean, extract M values for which the boolean is true and it is the last true value in a column. For example:

m = magic(4);
i = (m > 10);

% m =
% 16     2     3    13
%  5    11    10     8
%  9     7     6    12
%  4    14    15     1

% i =
% 1   0   0   1
% 0   1   0   0
% 0   0   0   1
% 0   1   1   0

And the expected output:

% i_ =
% 1   0   0   0
% 0   0   0   0
% 0   0   0   1
% 0   1   1   0

% x = [16, 14, 15, 12]

I know this could be easily achieved by looping through the columns and using find, but in my experience there often are better ways of formulating these problems.

Upvotes: 4

Views: 204

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112759

Here's another way, using accumarray:

[~, col] = find(i); % column indices
lin = find(i); % linear indices
x = accumarray(col, m(lin), [], @(x) x(end));

Upvotes: 2

rahnema1
rahnema1

Reputation: 15867

You can use the second output of max to find the last true element of each column. Before that the logical matrx should be multiplied by an increasing column vector.

[~, idx] = max((1:size(i, 1)).' .* i, [], 1, 'linear') ;
x = m(idx) ;

Upvotes: 3

kkuilla
kkuilla

Reputation: 2256

This would do it

m(max(i.*reshape([1:numel(m)],size(m))))

Explanation

So we are generating an array of indices

reshape([1:numel(m)],size(m))

ans =

1    5    9   13
2    6   10   14
3    7   11   15
4    8   12   16

That represents the indices for each value. The we multiply that with I to get the values we are interested in

i.*reshape([1:numel(m)],size(m))
ans =

1    0    0   13
0    6    0    0
0    0    0   15
0    8   12    0

Then we do a max on that since max works on columns. This will give us the last index in each column.

max(i.*reshape([1:numel(m)],size(m)))
ans =

1    8   12   15

Then apply those indices on m to get the values

m(max(i.*reshape([1:numel(m)],size(m))))
ans =

   16   14   15   12

Upvotes: 3

Related Questions