repeat vector elements and operate on them

3 ビュー (過去 30 日間)
MatG
MatG 2021 年 10 月 6 日
コメント済み: MatG 2021 年 10 月 7 日
I have column vectors A = [a1;a2;...;an] and B = [b1;b2;...;bn] where B elements are integer numbers. I want a fast way to generate a vector D such that D = [a1+0 ; a1+1 ; a1+2 ; a1+b1-1 ; a2+0 ; a2+1 ; ...; a2+ b2 -1; ... ; an+0 ; an+1 ; ... ; an+bn-1]. An example is below. So far, I know I can use "repelem(A,B) to make sure matrix C has the right number of rows; howver, I don't know what to do next (whether using C or an entirely new idea).
A=[12; 10; 5];
B=[4;3;2];
C=repelem(A,B);
% I want D=[ 12 ; 13; 14 ; 15 ; 10 ; 11 ; 12 ; 5 ; 6]
VectorA = [[3;4;5]

採用された回答

Matt J
Matt J 2021 年 10 月 6 日
編集済み: Matt J 2021 年 10 月 6 日
A=[12; 10; 5];
B=[4;3;2];
C=repelem(A-1,B);
T=ones(size(C));
I=B(1:end-1);
T(cumsum(I)+1)=1-I;
D=C+cumsum(T);
D.'
ans = 1×9
12 13 14 15 10 11 12 5 6
  1 件のコメント
Jan
Jan 2021 年 10 月 6 日
編集済み: Jan 2021 年 10 月 6 日
This method is 60 times faster than the arrayfun approach and 10 times faster than the loop. Nice!

サインインしてコメントする。

その他の回答 (1 件)

Jan
Jan 2021 年 10 月 6 日
編集済み: Jan 2021 年 10 月 6 日
Start with a simple loop:
A = [12; 10; 5];
B = [4; 3; 2];
RepSum(A, B)
function C = RepSum(A, B)
len = sum(B);
C = zeros(len, 1);
i1 = 1;
for k = 1:numel(A)
i2 = i1 + B(k) - 1;
C(i1:i2) = A(k):A(k) + B(k) - 1;
i1 = i2 + 1;
end
end
And a C-Mex version:
// RepSumX.c, Compile with: mex -O -R2018a RepSumX.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mwSize nA, i, j, b;
double *A, *B, *C, v;
nA = mxGetNumberOfElements(prhs[0]);
A = mxGetDoubles(prhs[0]);
B = mxGetDoubles(prhs[1]);
v = 0.0;
for (i = 0; i < nA; v += B[i++]) ;
plhs[0] = mxCreateDoubleMatrix((mwSize) v, 1, mxREAL);
C = mxGetDoubles(plhs[0]);
for (i = 0; i < nA; i++) {
v = A[i];
b = (mwSize) B[i];
while (b--) {
*C++ = v++;
}
}
}
And the timings for 1e6 elements on my R2018b i5 machine:
A = randi([1, 1000], 1e6, 1);
B = randi([1, 20], 1e6, 1);
tic
C1 = RepSum(A,B);
toc
tic
F = @(a, b) a + (0:b-1).';
C2 = cell2mat(arrayfun(F, A, B, 'uni', 0));
toc
tic
C = repelem(A,B);
T = ones(size(C));
T(cumsum(B(1:end-1))+1) = 1 - B(1:end-1);
C3 = C + cumsum(T) - 1;
toc
tic
C4 = RepSumX(A, B);
toc
isequal(C1, C2, C3, C4) % 1
% Elapsed time is 1.234160 seconds. Loop
% Elapsed time is 7.517230 seconds. Arrayfun (Stephen)
% Elapsed time is 0.134246 seconds. cumsum (Matt J)
% Elapsed time is 0.032087 seconds. C-mex
  1 件のコメント
MatG
MatG 2021 年 10 月 7 日
Thanks @Jan for benchmarking. I'll adjust the accepted answer to the fastest pure MATLAB one by @Matt J. Thanks a lot for mexing.

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeCreating and Concatenating Matrices についてさらに検索

タグ

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by