Reputation: 83
Given an integer n, I would like to get the vector as follows. E.g. if n=3
, then vector should be [1,1,2,1,2,3]
and if n=4
, then vector should be [1,1,2,1,2,3,1,2,3,4]
, and so on. Is there a simple way to do it? Thanks.
Upvotes: 4
Views: 325
Reputation: 10792
Using a sparse matrix we can do:
p = 1:4;
x = cumsum(sparse(1,cumsum(p)+1,-p)+1);
x(end) = []
Result:
x =
1 1 2 1 2 3 1 2 3 4
The biggest advantage of this method is that it also work with unordered sequence length:
p = [2 3 2 4];
x = cumsum(sparse(1,cumsum(p)+1,-p)+1);
x(end) = []
Result:
x =
1 2 1 2 3 1 2 1 2 3 4
Upvotes: 0
Reputation: 21563
Here are three other methods. I expect them to be more memory efficient than the vectorized solution by @A. Donda or @Mohsen, but of course for n = 1000 or less that is not likely a concern.
The most interesting part is the speed difference between the two methods, the second and third can also work for n=10000
in under a second but the first is much slower!
n = 1000;
% Slow vector growing
tic
v=[];
for t = 1:n
v = [v 1:t];
end
toc % 0.6 sec
tic
% Fast vector growing
v=[];
for t = 1:n
x = 1:t;
v(end+x) = x;
end
toc % 0.01 sec
tic
% Preallocated loop
v=zeros(n*(n+1)/2,1);
count = 0;
for t = 1:n
x = 1:t;
v(count+x) = x;
count = count+t;
end
toc % 0.01 sec as well
Upvotes: 1
Reputation: 9864
You get a fast solution using this
w=ones(1,n*(n+1)/2);
w(1+cumsum(1:n-1))=-(0:n-2);
w=cumsum(w);
On my machine, Dennis's solution is fastest for n<=8
, but after that this method is the fastest.
Using this benchmarking code:
n=2000;
N=1e6/n;
tic
for k=1:N
A = repmat((1 : n)', 1, n);
A = A(triu(ones(n)) ~= 0);
end
toc
tic
for k=1:N
w=ones(1,n*(n+1)/2);
w(1+cumsum(1:n-1))=-(0:n-2);
w=cumsum(w);
end
toc
tic
for k=1:N
%// Fast vector growing
v=[];
for t = 1:n
x = 1:t;
v(end+x) = x;
end
end
toc
For n=4
Elapsed time is 5.688693 seconds.
Elapsed time is 3.576366 seconds.
Elapsed time is 1.878887 seconds.
For n=8
Elapsed time is 2.985184 seconds.
Elapsed time is 1.851967 seconds.
Elapsed time is 1.834574 seconds.
For n=100
Elapsed time is 1.084404 seconds.
Elapsed time is 0.352033 seconds.
Elapsed time is 2.502724 seconds.
For n=1000
Elapsed time is 15.625361 seconds.
Elapsed time is 3.949131 seconds.
Elapsed time is 11.497764 seconds.
For n=2000
Elapsed time is 29.940548 seconds.
Elapsed time is 7.649394 seconds.
Elapsed time is 22.846367 seconds.
Upvotes: 3
Reputation: 8467
Here's a solution that uses the "upper triangular matrix" function to select the needed entries from a simple repetition of the full sequence:
A = triu(repmat((1 : n)', 1, n));
A = A(A ~= 0)'
triu
sets everything below the diagonal to zero. This approach only works if the original sequence doesn't include zeros, which of course is given for 1 : n
. Still, a better solution might be to use the result of triu
only for indexing:
A = repmat((1 : n)', 1, n);
A = A(triu(ones(n)) ~= 0);
This is pretty fast, below 1 second runtime for n = 10,000 on my machine.
As Dennis Jaheruddin pointed out, this approach needs a bit less than twice as much memory temporarily than is needed for the result (the precise factor is 2 n / (n + 1)).
Upvotes: 2