简体   繁体   中英

Vector creation based on each element of a vector - Matlab

I want to apply a linespace function for each element of a vector, and create a whole vector in the end, is there some way convenient to do it?

Specifically,I want to create matrix B by matrix A without using a loop, where A = [1; 2; 3; 4] B = [1; 1; 2; 1; 2; 3; 1; 2; 3; 4] A = [1; 2; 3; 4] B = [1; 1; 2; 1; 2; 3; 1; 2; 3; 4]

As you can see, if the third element in the vector is 3 , then the "third vector" in the output vector B will be [1:1:3]. The step I desired is fixed and will be exact 1 for any element.

Could anyone help me, please?

Because of the dynamic nature of B , there is no way you can do it without any loops. I would not shy away from loops in this case - especially for more recent versions of MATLAB with their improved JIT compiler. Loops are now quite competitive over vectorized operations depending on what exactly you want to do.

The easiest approach would be to loop over all values of A and the colon operator and go from 1 up to each value in A .

Something like this would work:

A = [1; 2; 3; 4];
B = [];

for v = 1 : numel(A)
    B = [B; (1:A(v)).'];
end

At each iteration, we find a value in A and create a vector that goes from 1 up to the value. We concatenate all of these into a single vector. Keep in mind that no error checking is performed so we're assuming that every value in A is greater than or equal to 1.

If you're keen on a one liner, it's possible to do this with arrayfun to create a bunch of cell arrays and squeeze them together, but performance wise this may not be the best solution:

A = [1; 2; 3; 4];
B = cell2mat(arrayfun(@(x) (1:x).', A, 'un', 0));

arrayfun takes in a function to operate on each input element in A , so the function would be to create a column vector from 1 up to the desired value. un is short for UniformOutput and it is set to 0 meaning that the output is not uniform, so we're going to output a bunch of cell arrays - one for each vector you've created. Finally, cell2mat squeezes all of the cell arrays together to create a single column vector. It's more elegant, but performance wise it may not be so as there is a lot of overhead.

Here are two ways that avoid loops.

  • Using bsxfun : this approach is memory- (and perhaps time-) inefficient:

     t = 1:max(A); B = nonzeros(bsxfun(@times, t.', bsxfun(@le, t.', t))); 
  • Using cumsum : this is memory-efficient, but a little more convoluted:

     A = nonzeros(A); % remove zeros, if any B = ones(1, sum(A)); % initiallize B(cumsum(A(1:end-1))+1) = 1-A(1:end-1); % write appropriate values... B = cumsum(B).'; % ... so that the cumulative sum gives the desired output 

A loop is probably the best way: simplest and clearest.

You can do it using a for loop as follows:

B = [];
for ii=1:size(A)
    B = [B;(1:A(ii))'];
end

Result

B = [1; 1; 2; 1; 2; 3; 1; 2; 3; 4]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM