Claude
Claude

Reputation: 1784

Index a vector by a matrix of conditions to obtain multiple selections of the target?

I have a vector T of length n and m other vectors of the same length with 0 or 1 used as condition to select elements of T. The condition vectors are combined into a matrix I of size n x m.

Is there a one liner to extract a matrix M of values from Tsuch that the i-th column of M are those elements in T that are selected by the condition elements of the i-th column in I?

Example:

T = (1:10)'
I = mod(T,2) == 0
T(I)'

yields

2    4    6    8   10

However

I = mod(T,2:4) == 0
T(I)'

yields an error in the last statement. I see that the columns might select a different number of elements which results in vectors of different lengths (as in the example). However, even this example doesn't work:

I = zeros(10,2)
I(:,1) = mod(T,2)==0
I(:,2) = mod(T,2)==1

Is there any way to achieve the solution in a one liner?

Upvotes: 1

Views: 66

Answers (3)

Matt
Matt

Reputation: 2802

The easiest way I can think of to do something like this is to take advantage of the element-wise multiplication operator .* with your matrix I. Take this as an example:

% these lines are just setup of your problem
m = 10;
n = 10;
T = [1:m]';
I = randi([0 1], m, n);
% 1 liner to create M
M = repmat(T, 1, n) .* I;

What this does is expand T to be the same size as I using repmat and then multiplies all the elements together using .*.

Upvotes: 3

Some Guy
Some Guy

Reputation: 1797

One line solution using cellfun and mat2cell

nColumns = size(I,2); nRows = size(T,1); % Take the liberty of a line to write cleaner code
cellfun(@(i)T(i),mat2cell(I,nRows,ones(nColumns,1)),'uni',0)

What is going on:

@(i)T(i) % defines a function handle that takes a logical index and returns elements from T for those indexes

mat2cell(I,nRows,ones(nColumns,1)) % Split I such that every column is a cell

'uni',0 % Tell cellfun that the function returns non uniform output

Upvotes: 1

rahnema1
rahnema1

Reputation: 15857

Here is a one linear solution

mat2cell(T(nonzeros(bsxfun(@times,I,(1:numel(T)).'))),sum(I))

First logical index should be converted to numeric index for it we multiply T by each column of I

 idx = bsxfun(@times,I,(1:numel(T)).');

But that index contain zeros we should extract those values that correspond to 1s in matrix I:

 idx = nonzeros(idx);

Then we extract repeated elements of T :

T2 = T(idx);

so we need to split T2 to 3 parts size of each part is equal to sum of elements of corresponding column of I and mat2cell is very helpful

result = mat2cell(T2,sum(I));

result

ans =
{
  [1,1] =

      2
      4
      6
      8
     10

  [2,1] =

     3
     6
     9

  [3,1] =

     4
     8

}

Upvotes: 1

Related Questions