repeat vector elements and operate on them

조회 수: 1 (최근 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 CenterFile Exchange에서 Creating and Concatenating Matrices에 대해 자세히 알아보기

태그

Community Treasure Hunt

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

Start Hunting!

Translated by