多个起点和终点的高效冒号运算符

时间:2016-07-21 10:03:57

标签: matlab vectorization simulink

假设我有以下两个变量:

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

我想有效(如果可能的话,没有for循环)生成一行,该行包含在start_idxend_idx的相应元素之间应用的冒号运算符。对于此示例,这将导致:

result = [1:2 4:6 7:15];

因此:

results = [1 2 4 5 6 7 8 9 10 11 12 13 14 15];

执行此操作的方法应该可以在Simulink的MATLAB功能块中使用。非常感谢你!

4 个答案:

答案 0 :(得分:4)

这是一种基于累积求和的矢量化方法 -

% 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)

示例运行 -

start_idx =
     6     8    13
end_idx =
    11    11    15
out =
     6     7     8     9    10    11     8     9    10    11    13    14    15

答案 1 :(得分:1)

正如我在评论中指出的那样,解决这个问题的一个方法是:

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

arrayfun调用将创建一个单元格数组,其中每个单元格都是输出的一部分:

ans =

     1     2


ans =

     4     5     6


ans =

  Columns 1 through 8

     7     8     9    10    11    12    13    14

  Column 9

    15

通过将其包含在cell2mat调用中,您可以获得预期的输出:

out =

  Columns 1 through 8

     1     2     4     5     6     7     8     9

  Columns 9 through 14

    10    11    12    13    14    15

答案 2 :(得分:1)

这很麻烦,但也许更快:

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);

它正确处理空范围,即

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

给出

result =
     1     2     4     5     6

答案 3 :(得分:1)

如果您测量这段代码的经过时间,在清除工作区后,您将看到它平均需要0.004秒,而Divakar的代码也大致相同,即0.007秒。

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

如您所见,我使用了较长的开始和结束idx数组,并确保结束数组元素与它们各自的起始数组元素相距很远。

命令'toc'之后经过的时间总是根据CPU上的负载而变化。当我测量时间时,除了MATLAB之外我只打开了1-2个应用程序并在执行此代码之前清除了工作空间。 final_arr的计数为~24k,但处理输出所需的时间并不多。

希望它有所帮助。