从开始和结束数字的向量创建一个序列
Create a sequence from vectors of start and end numbers
如果我在 Matlab 中以矢量化方式拥有子序列的起始和结束数字向量,如何创建一个序列?
示例输入:
A=[12 20 34]
B=[18 25 37]
我想得到(为清楚起见,留出空格):
C=[12 13 14 15 16 17 18 20 21 22 23 24 25 34 35 36 37]
这是一个选项:
C = cell2mat(cellfun(@(a,b){a:b},num2cell(A),num2cell(B)));
假设 A
和 B
升序排列并且 B(i) < A(i+1)
成立,那么:
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx))
解决 Dennis 在评论中提到的问题:
m = min(A)-1;
A = A-m;
B = B-m;
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx)) + m;
你可以这样做:
C = cell2mat(arrayfun(@(a,b)a:b, A, B, "UniformOutput", false))
arrayfun(...)
创建所有采用 A 和 B 对的子序列。
cell2mat
用于连接每个子序列。
cumsum
针对一般情况(负数或重叠)的基于方法 -
%// Positions in intended output array at which group shifts
intv = cumsum([1 B-A+1])
%// Values to be put at those places with intention of doing cumsum at the end
put_vals = [A(1) A(2:end) - B(1:end-1)]
%// Get vector of ones and put_vals
id_arr = ones(1,intv(end)-1)
id_arr(intv(1:end-1)) = put_vals
%// Final output with cumsum of id_arr
out = cumsum(id_arr)
样本运行-
>> A,B
A =
-2 -3 1
B =
5 -1 3
>> out
out =
-2 -1 0 1 2 3 4 5 -3 -2 -1 1 2 3
基准测试
这是 warming-up tic-toc
之后的 运行 时间测试,用于比较列出的各种解决大型 A
和 B
-
问题的方法
%// Create inputs
A = round(linspace(1,400000000,200000));
B = round((A(1:end-1) + A(2:end))/2);
B = [B A(end)+B(1)];
disp('------------------ Divakar Method')
.... Proposed approach in this solution
disp('------------------ Dan Method')
tic
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx));
toc, clear C idx
disp('------------------ Santhan Method')
tic
In = [A;B];
difIn = diff(In);
out1 = bsxfun(@plus, (0:max(difIn)).',A); %//'
mask = bsxfun(@le, (1:max(difIn)+1).',difIn+1); %//'
out1 = out1(mask).'; %//'
toc, clear out1 mask difIn In
disp('------------------ Itamar Method')
tic
C = cell2mat(cellfun(@(a,b){a:b},num2cell(A),num2cell(B)));
toc, clear C
disp('------------------ dlavila Method')
tic
C = cell2mat(arrayfun(@(a,b)a:b, A, B, 'UniformOutput', false));
toc
运行时间
------------------ Divakar Method
Elapsed time is 0.793758 seconds.
------------------ Dan Method
Elapsed time is 2.640529 seconds.
------------------ Santhan Method
Elapsed time is 1.662889 seconds.
------------------ Itamar Method
Elapsed time is 2.524527 seconds.
------------------ dlavila Method
Elapsed time is 2.096454 seconds.
替代使用 bsxfun
%// Find the difference between Inputs
difIn = B - A;
%// Do colon on A to A+max(difIn)
out = bsxfun(@plus, (0:max(difIn)).',A); %//'
%// mask out which values you want
mask = bsxfun(@le, (1:max(difIn)+1).',difIn+1); %//'
%// getting only the masked values
out = out(mask).'
结果:
>> A,B
A =
-2 -4 1
B =
5 -3 3
>> out
out =
-2 -1 0 1 2 3 4 5 -4 -3 1 2 3
如果我在 Matlab 中以矢量化方式拥有子序列的起始和结束数字向量,如何创建一个序列?
示例输入:
A=[12 20 34]
B=[18 25 37]
我想得到(为清楚起见,留出空格):
C=[12 13 14 15 16 17 18 20 21 22 23 24 25 34 35 36 37]
这是一个选项:
C = cell2mat(cellfun(@(a,b){a:b},num2cell(A),num2cell(B)));
假设 A
和 B
升序排列并且 B(i) < A(i+1)
成立,那么:
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx))
解决 Dennis 在评论中提到的问题:
m = min(A)-1;
A = A-m;
B = B-m;
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx)) + m;
你可以这样做:
C = cell2mat(arrayfun(@(a,b)a:b, A, B, "UniformOutput", false))
arrayfun(...)
创建所有采用 A 和 B 对的子序列。
cell2mat
用于连接每个子序列。
cumsum
针对一般情况(负数或重叠)的基于方法 -
%// Positions in intended output array at which group shifts
intv = cumsum([1 B-A+1])
%// Values to be put at those places with intention of doing cumsum at the end
put_vals = [A(1) A(2:end) - B(1:end-1)]
%// Get vector of ones and put_vals
id_arr = ones(1,intv(end)-1)
id_arr(intv(1:end-1)) = put_vals
%// Final output with cumsum of id_arr
out = cumsum(id_arr)
样本运行-
>> A,B
A =
-2 -3 1
B =
5 -1 3
>> out
out =
-2 -1 0 1 2 3 4 5 -3 -2 -1 1 2 3
基准测试
这是 warming-up tic-toc
之后的 运行 时间测试,用于比较列出的各种解决大型 A
和 B
-
%// Create inputs
A = round(linspace(1,400000000,200000));
B = round((A(1:end-1) + A(2:end))/2);
B = [B A(end)+B(1)];
disp('------------------ Divakar Method')
.... Proposed approach in this solution
disp('------------------ Dan Method')
tic
idx = zeros(1,max(B)+1);
idx(A) = 1;
idx(B+1) = -1;
C = find(cumsum(idx));
toc, clear C idx
disp('------------------ Santhan Method')
tic
In = [A;B];
difIn = diff(In);
out1 = bsxfun(@plus, (0:max(difIn)).',A); %//'
mask = bsxfun(@le, (1:max(difIn)+1).',difIn+1); %//'
out1 = out1(mask).'; %//'
toc, clear out1 mask difIn In
disp('------------------ Itamar Method')
tic
C = cell2mat(cellfun(@(a,b){a:b},num2cell(A),num2cell(B)));
toc, clear C
disp('------------------ dlavila Method')
tic
C = cell2mat(arrayfun(@(a,b)a:b, A, B, 'UniformOutput', false));
toc
运行时间
------------------ Divakar Method
Elapsed time is 0.793758 seconds.
------------------ Dan Method
Elapsed time is 2.640529 seconds.
------------------ Santhan Method
Elapsed time is 1.662889 seconds.
------------------ Itamar Method
Elapsed time is 2.524527 seconds.
------------------ dlavila Method
Elapsed time is 2.096454 seconds.
替代使用 bsxfun
%// Find the difference between Inputs
difIn = B - A;
%// Do colon on A to A+max(difIn)
out = bsxfun(@plus, (0:max(difIn)).',A); %//'
%// mask out which values you want
mask = bsxfun(@le, (1:max(difIn)+1).',difIn+1); %//'
%// getting only the masked values
out = out(mask).'
结果:
>> A,B
A =
-2 -4 1
B =
5 -3 3
>> out
out =
-2 -1 0 1 2 3 4 5 -4 -3 1 2 3