How to generate a single vector of block-consecutive values from 2 vectors of same size without a loop ?
2 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
jyloup p
el 16 de Jun. de 2014
Comentada: Amro
el 20 de Jun. de 2014
Hello, I have 2 vectors of same size let's say a = [3 7 19 22] and b = [5 10 20 24]
And from those 2 vectors I want to generate without a loop a single vector:
v = [a(1):b(1) a(2):b(2) ... a(end):b(end)].
so here v=[3 4 5 7 8 9 10 19 20 22 23 24].
I found linspaceNDim(a,b,N) on File Exchange Linearly spaced multidimensional matrix without loop but it doesn't work here as I dont want a fixed number of values between a(i) and b(i), but only block-consecutive values : a(i):b(i). So here N is changing at each index i.
I tried a:.b but this syntax doesn't work on Matlab.
Thanks for you help.
1 comentario
Amro
el 20 de Jun. de 2014
here is a similar question on Stack Overflow: Vectorized array creation from a list of start/end indices
Respuesta aceptada
José-Luis
el 16 de Jun. de 2014
Editada: José-Luis
el 17 de Jun. de 2014
Any particular reason you don't want to use a loop? This is one of those cases where you should use one, if performance is an issue. Arrayfun() is just syntactic sugar around a loop. Plus the added overheads of invoking cell arrays:
a = [3 7 19 22];
b = [5 10 20 24];
tic
your_mat = cell2mat(arrayfun(@(x,y) x:y,a,b,'uniformoutput',false));
toc
tic
numEl = b - a;
pos = 1;
your_data = NaN * ones(sum(numEl),1);
for ii = 1:numel(numEl)
your_data(pos:pos+numEl(ii)) = a(ii):b(ii);
pos = pos + numEl(ii) + 1;
end
toc
Elapsed time is 0.000602 seconds.
Elapsed time is 0.000038 seconds.
EDIT
I had made a mistake, the pre-allocation should read:
your_data = NaN * ones(sum(numEl) + numel(numEl),1);
EDIT
A bit cleaner:
vals = reshape(sort(randperm(10^6,1000)),2,[]);
a = vals(1,:);
b = vals(2,:);
tic
offset = b - a;
numVal = sum(offset + 1);
pos = 1;
your_data = ones(numVal,1);
for ii = 1:numel(offset)
your_data(pos:pos+offset(ii)) = a(ii):b(ii);
pos = pos + offset(ii) + 1;
end
toc
2 comentarios
José-Luis
el 17 de Jun. de 2014
I had done the pre-allocation wrong. Please replace by:
your_data = ones(b(end),1);
or
your_data = (sum(numEl) + numel(numEl),1);
Más respuestas (6)
Andrei Bobrov
el 16 de Jun. de 2014
Editada: Andrei Bobrov
el 17 de Jun. de 2014
v = a(1):b(end);
v = v(any(bsxfun(@ge,v,a.')&bsxfun(@le,v,b.')));
other variant
zo = zeros(b(end) - a(1) + 2,1);
zo(a - a(1) + 1) = 1;
zo(b - a(1) + 2) = -1;
t = cumsum(zo(1:end-1)) > 0;
out = a(1):b(end);
v = out(t);
0 comentarios
Sean de Wolski
el 17 de Jun. de 2014
Editada: Sean de Wolski
el 17 de Jun. de 2014
There's also FEX:mcolon which does exactly what you're looking for and has a mex implementation that may very well be the fastest.
Azzi Abdelmalek
el 16 de Jun. de 2014
Editada: Azzi Abdelmalek
el 16 de Jun. de 2014
cell2mat(arrayfun(@(x,y) x:y,a,b,'un',0))
1 comentario
jyloup p
el 17 de Jun. de 2014
2 comentarios
José-Luis
el 17 de Jun. de 2014
Editada: José-Luis
el 17 de Jun. de 2014
That's not a fair comparison. If you generate your limits like that, with common intervals, then the for loop produces garbage. Also the pre-allocation becomes meaningless and the output keeps changing size, leading to poor performance.
If the data is set with non-overlapping intervals, like in the original question, then the loop is still faster:
vals = reshape(sort(randperm(10^6,1000)),2,[]);
a = vals(1,:);
b = vals(2,:);
tic
offset = b - a;
numVal = sum(offset + 1);
pos = 1;
your_data = ones(numVal,1);
for ii = 1:numel(offset)
your_data(pos:pos+offset(ii)) = a(ii):b(ii);
pos = pos + offset(ii) + 1;
end
toc
tic
zo = zeros(b(end) - a(1) + 2,1);
zo(a - a(1) + 1) = 1;
zo(b - a(1) + 2) = -1;
t = cumsum(zo(1:end-1)) > 0;
out = a(1):b(end);
v = out(t);
toc
Elapsed time is 0.003596 seconds.
Elapsed time is 0.024514 seconds.
That being said, I am always impressed by Andrei's tricks.
Ver también
Categorías
Más información sobre Logical en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!