Matrix creation Octave / Matlab, loopless solution

2019-05-20 07:53发布

问题:

I want to create a matrix like

A = [0 0 0 0 1;
     0 0 0 1 1;
     0 0 0 1 1;
     0 0 0 1 1;
     0 0 1 1 1;
     0 1 1 1 1]

based on a vector indicating how many '0's should precede '1's on each row:

B = [4 3 3 3 2 1]

Is there a loopless way to do this ?

回答1:

You don't mention in your question how the horizontal size of the array should be defined (the number of ones).

For predefined width you can use this code:

width = 5;

A = cell2mat(arrayfun(@(x) [ zeros(1,x), ones(1,width-x) ], B, 'UniformOutput', false)');

If you want that A has minimal width, but still at least one 1 in every row:

A = cell2mat(arrayfun(@(x) [ zeros(1,x), ones(1,max(B)+1-x) ], B, 'UniformOutput', false)');


回答2:

A shorter “old-school” way to achieve this without a loop would be as follows:

A = repmat(B',1,max(B)+1)<repmat([1:max(B)+1],size(B,2),1)

If you want to have a minimum number of ones

min_ones=1; %or whatever
A = repmat(B',1,max(B)+min_ones)<repmat([1:max(B)+min_ones],size(B,2),1)

I don’t know how this compares speedwise to @nrz’s approach (I’ve only got Octave to hand right now), but to me it's more intuitive as it’s simply comparing a max(B) + min_ones * column tiling of B:

4  4  4  4  4
3  3  3  3  3
3  3  3  3  3
3  3  3  3  3
2  2  2  2  2
1  1  1  1  1

with a row tiling of [1 : max(B) + min_ones]

1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5

To generate:

A =

  0  0  0  0  1
  0  0  0  1  1
  0  0  0  1  1
  0  0  0  1  1
  0  0  1  1  1
  0  1  1  1  1


回答3:

This requires only one line, and seems to be faster than previous solutions based on repmat or arrayfun:

%// Example data
ncols = 5;
B = [4 3 3 3 2 1];

%// Generate A
A = bsxfun(@gt, 1:ncols, B(:));