Efficient colon operator for multiple start and end points

后端 未结 4 1722
我寻月下人不归
我寻月下人不归 2020-12-06 13:21

Suppose I have the following two variables:

start_idx = [1 4 7];
end_idx   = [2 6 15];

I want to efficiently (no for loop

相关标签:
4条回答
  • 2020-12-06 13:51

    Here's a vectorized approach based on cumulative summation -

    % Get lengths of each group
    lens = end_idx - start_idx + 1;
    
    % Determine positions in o/p array where groups would shift
    shift_idx = cumsum(lens(1:end-1))+1
    
    % Initialize ID array and at shifting positions place strategically created
    % numbers, such that when ID array is cumulatively summed would result in
    % desired "ramped" array
    id_arr = ones(1,sum(lens));
    id_arr([1 shift_idx]) = [start_idx(1) start_idx(2:end) - end_idx(1:end-1)];
    out = cumsum(id_arr)
    

    Sample run -

    start_idx =
         6     8    13
    end_idx =
        11    11    15
    out =
         6     7     8     9    10    11     8     9    10    11    13    14    15
    
    0 讨论(0)
  • 2020-12-06 13:51

    As I indicated in the comments, a one liner to solve this would be :

    out=cell2mat(arrayfun(@(x,y)[x:y],start_idx,end_idx,'uniformoutput',false));
    

    The arrayfun call will create a cell array whose each cell is a part of your output :

    ans =
    
         1     2
    
    
    ans =
    
         4     5     6
    
    
    ans =
    
      Columns 1 through 8
    
         7     8     9    10    11    12    13    14
    
      Column 9
    
        15
    

    By wrapping it inside a cell2mat call you get the expected output :

    out =
    
      Columns 1 through 8
    
         1     2     4     5     6     7     8     9
    
      Columns 9 through 14
    
        10    11    12    13    14    15
    
    0 讨论(0)
  • 2020-12-06 13:54

    If you measure the elapsed time for this piece of code, after clearing the workspace, you will see that it takes an average of 0.004 sec while Divakar's code also takes roughly the same amount i.e. 0.007 sec..

    start_idx=[2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44];
    end_idx=[100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 ...
    1400 1500 1600 1700 1800 1900 2000 2100 2200];
    tic
    final_arr=[];
    for i=1:length(start_idx)
    final_arr=[final_arr,start_idx(i):end_idx(i)];
    end
    toc
    final_arr
    

    As you can see, I have used start and end idx arrays of longer length and made sure that the end array elements are very far away from their respective start array elements.

    The elapsed time which comes after the command 'toc' always changes according to the load on the CPU.. When I measure the time, I had only 1-2 apps open other than MATLAB and cleared the workspace before executing this code. The final_arr has a count of ~24k elements yet the time it took to process the output is not very much.

    Hope it helps.

    0 讨论(0)
  • 2020-12-06 14:07

    This is cumbersome, but perhaps faster:

    x = min(start_idx):max(end_idx);
    m = sum(bsxfun(@ge,x,start_idx(:)),1)==numel(end_idx)-sum(bsxfun(@le,x,end_idx(:)),1)+1;
    result = x(m);
    

    It correctly handles empty ranges, i.e.

    start_idx = [1 4 16]
    end_idx   = [2 6 15];
    

    gives

    result =
         1     2     4     5     6
    
    0 讨论(0)
提交回复
热议问题