How to generate a single vector of block-consecutive values from 2 vectors of same size without a loop ?
Afficher commentaires plus anciens
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 commentaire
Amro
le 20 Juin 2014
here is a similar question on Stack Overflow: Vectorized array creation from a list of start/end indices
Réponse acceptée
Plus de réponses (6)
Andrei Bobrov
le 16 Juin 2014
Modifié(e) : Andrei Bobrov
le 17 Juin 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);
Sean de Wolski
le 17 Juin 2014
Modifié(e) : Sean de Wolski
le 17 Juin 2014
2 votes
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
le 16 Juin 2014
Modifié(e) : Azzi Abdelmalek
le 16 Juin 2014
cell2mat(arrayfun(@(x,y) x:y,a,b,'un',0))
1 commentaire
Amro
le 20 Juin 2014
slightly simplified: cell2mat(arrayfun(@colon,a,b,'un',0))
jyloup p
le 16 Juin 2014
0 votes
jyloup p
le 17 Juin 2014
2 commentaires
jyloup p
le 17 Juin 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.
Catégories
En savoir plus sur Loops and Conditional Statements dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!