Another suggestion without a loop.
First count the number of repeated values
a=histc(v1,unique(v1));
Construct counting array
b = ones(1,sum(a));
Now counter the cumulated sum the appropriate places:
a = a(1:end-1);
b(cumsum(a)+1) = b(cumsum(a)+1) - a;
finally take the cumulated sum
cumsum(b)
In total
v1 = [1,1,1,1,2,2,3,3,3,3,3,4];
a=histcounts(v1,[unique(v1),inf]);
b = ones(1,sum(a));
a = a(1:end-1);
b(cumsum(a)+1) = b(cumsum(a)+1) - a;
disp(cumsum(b))
TIMEITs:
Running on random sorted input V1 = sort(randi(100,1e6,1));
I obtain the following timings in Matlab 2017a.
- Gnovic's first suggestion: 2.852872e-02
- Gnovic's second suggestion: 2.909344e-02
- AVK's suggestion: 3.935982e-01
- RadioJava's suggestion: 2.441206e-02
- Nicky's suggestion: 9.153147e-03
Code for reference:
function [] = SO()
V1 = sort(randi(100,1e6,1));
t1 = timeit(@() gnovice1(V1)); fprintf("* Gnovic's first suggestion: %d\n",t1);
t2 = timeit(@() gnovice2(V1)); fprintf("* Gnovic's second suggestion: %d\n",t2);
t3 = timeit(@() AVK(V1)); fprintf("* AVK's suggestion: %d\n",t3);
t4 = timeit(@() RadioJava(V1)); fprintf("* RadioJava's suggestion: %d\n",t4);
t5 = timeit(@() Nicky(V1)); fprintf("* Nicky's suggestion: %d\n",t5);
function []=gnovice1(V1)
V2 = accumarray(V1, 1, [], @(x) {1:numel(x)});
V2 = [V2{:}].';
function []=gnovice2(V1)
V2 = ones(size(V1));
V2([find(diff(V1))+1; end]) = 1-accumarray(V1, 1);
V2 = cumsum(V2(1:end-1));
function []=AVK(v)
a= v;
for i=unique(v)'
a(v==i)= 1:length(a(v==i));
end
function []=RadioJava(vec)
vec = vec(:).';
zero_separated=[1,vec(1:end-1)==vec(2:end)];
c=cumsum(zero_separated);
zeros_ind = ~zero_separated;
d = diff([1 c(zeros_ind)]);
zero_separated(zeros_ind) = -d;
output=cumsum(zero_separated);
function []=Nicky(v1)
v1 = v1(:).';
a=histcounts(v1,[unique(v1),inf]);
b = ones(1,sum(a));
a = a(1:end-1);
b(cumsum(a)+1) = b(cumsum(a)+1) - a;
b = cumsum(b);