How count NaN values and replace NaNs in a sequence with that number?

1 view (last 30 days)
Mr M. on 30 Jun 2018
Edited: Stephen23 on 30 Jun 2018
I have a vector [0 0 NaN 0 0 NaN NaN NaN 0 0 0 0 0 NaN] and I want [0 0 1 0 0 3 3 3 0 0 0 0 0 1]. Is it possible without a for cycle?

Guillaume on 30 Jun 2018
Edited: Guillaume on 30 Jun 2018
I don't think it's entirely possible to do it without a loop, but the loop can be limited to the number of sequences (3 steps in your example)
v = [0 0 NaN 0 0 NaN NaN NaN 0 0 0 0 0 NaN];
seqedges = find(diff([false, isnan(v), false]));
seqstarts = seqedges(1:2:end);
seqends = seqedges(2:2:end);
seqlengths = seqends - seqstarts;
for seq = 1:numel(seqstarts)
v(seqstarts(seq):seqends(seq)-1) = seqlengths(seq);
end
edit: actually, it's possible without a loop:
v = [0 0 NaN 0 0 NaN NaN NaN 0 0 0 0 0 NaN];
nanlocs = isnan(v);
seqedges = find(diff([false, nanlocs, false]));
seqlengths = seqedges(2:2:end) - seqedges(1:2:end);
v(nanlocs) = repelem(seqlengths, seqlengths)

Stephen23 on 30 Jun 2018
Edited: Stephen23 on 30 Jun 2018
No loops, no third-party functions, and works for all MATLAB versions:
>> V = [0 0 NaN 0 0 NaN NaN NaN 0 0 0 0 0 NaN];
>> X = isnan(V);
>> Y = cumsum(diff([0,X])>0);
>> D = diff([0,X,0]);
>> L = find(D<0)-find(D>0);
>> V(X) = L(Y(X))
V = 0 0 1 0 0 3 3 3 0 0 0 0 0 1

Jan on 30 Jun 2018
Edited: Jan on 30 Jun 2018
a = [0 0 NaN 0 0 NaN NaN NaN 0 0 0 0 0 NaN];
[b, n] = RunLength(isnan(a));
Result = RunLength(b .* n, n);
The C-Mex version runs very fast, but you have to compile it at first. But you can use the M-version included in this submission also: RunLength_M