MATLAB repeat numbers based on a vector of lengths

后端 未结 6 1298
失恋的感觉
失恋的感觉 2021-02-08 09:32

Is there a vectorised way to do the following? (shown by an example):

input_lengths = [ 1 1 1 4       3     2   1 ]
result =        [ 1 2 3 4 4 4 4 5 5 5 6 6 7 ]         


        
6条回答
  •  粉色の甜心
    2021-02-08 10:10

    I search an elegant solution, and I think David's solution is a good start. What I have in mind is that one can generate the indexes where to add one from previous element.

    For that, if we compute the cumsum of the input vector, we get:

    cumsum(input_lengths)
    ans = 1     2     3     7    10    12    13
    

    This is the indexes of the ends of sequences of identical numbers. That is not what we want, so we flip the vector twice to get the beginnings:

    fliplr(sum(input_lengths)+1-cumsum(fliplr(input_lengths)))
    ans = 1     2     3     4     8    11    13
    

    Here is the trick. You flip the vector, cumsum it to get the ends of the flipped vector, and then flip back; but you must substract the vector from the total length of the output vector (+1 because index starts at 1) because cumsum applies on the flipped vector.

    Once you have done this, it's very straightforward, you just have to put 1 at computed indexes and 0 elsewhere, and cumsum it:

    idx_begs = fliplr(sum(input_lengths)+1-cumsum(fliplr(input_lengths)));
    result = zeros(1,sum(input_lengths));
    result(idx_begs) = 1;
    result = cumsum(result);
    

    EDIT

    First, please have a look at Luis Mendo's solution, it is very close to mine but is more simpler and a bit faster (I won't edit mine even it is very close). I think at this date this is the fastest solution from all.

    Second, while looking at others solutions, I've made up another one-liner, a little different from my initial solution and from the other one-liner. Ok, this won't be very readable, so take a breath:

    result = cumsum( full(sparse(cumsum([1,input_lengths(1:end-1)]), ...
    ones(1,length(input_lengths)), 1, sum(input_lengths),1)) );
    

    I cut it on two lines. Ok now let's explain it.

    The similar part is to build the array of the indexes where to increment the value of the current element. I use the solution of Luis Mendo's for that. To build in one line the solution vector, I use here the fact that it is in fact a sparse representation of the binary vector, the one we will cumsum at the very end. This sparse vector is build using our computed index vector as x positions, a vector of 1 as y positions, and 1 as the value to put at these locations. A fourth argument is given to precise the total size of the vector (important if the last element of input_lengths is not 1). Then we get the full representation of this sparse vector (else the result is a sparse vector with no empty element) and we can cumsum.

    There is no use of this solution other than to give another solution to this problem. A benchmark can show that it is slower than my original solution, because of a heavier memory load.

提交回复
热议问题