# Fill out blanks with a upcoming number in a list?

I have a bunch of arrays looking like this:

{"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 300.348, 293.108, 285.86, 278.599, 271.39...

What is a good way of filling out the blanks with the next number? That is to assume that blanks simply mean the sequence of values is being constant. There may be blanks in between two numbers as well, not just at the beginning as in the sample above.

You could do something like this

list = Append[RandomReal[5, 30] /. a_ /; a < 2 :> "", 1.]

{3.82088, "", 2.17919, 2.38081, "", "", 4.54655, "", "", 3.97074, "",
3.72551, 4.75268, "", "", "", "", "", "", "", "", 2.74955, "", "",
4.98933, 2.40911, 3.72805, "", 4.50331, 4.75458, 1.}

Reverse[FoldList[#2 /. {"" -> #1} &, Last[list], Reverse[Most[list]]]]

{3.82088, 2.17919, 2.17919, 2.38081, 4.54655, 4.54655, 4.54655,
3.97074, 3.97074, 3.97074, 3.72551, 3.72551, 4.75268, 2.74955,
2.74955, 2.74955, 2.74955, 2.74955, 2.74955, 2.74955, 2.74955,
2.74955, 4.98933, 4.98933, 4.98933, 2.40911, 3.72805, 4.50331,
4.50331, 4.75458, 1.}


Here is a straightforward linear-time version

Flatten@Map[Replace[#, _ -> Last@#, {1}] &, Split[list, ! NumericQ@# &]]

• This solution has a problem when the last element of the list is blank. I commented under your solution, but the comment holds also for the solutions by Heike, Szabolcs and Artes. – VLC Mar 14 '12 at 16:52
• @vucko Yes, I am aware of that. But, if you think about it, in such case the problem is not well-formulated anyway, because it is not clear what should be the substitution. So, the best one can do within the given formulation is to include argument checks to filter out such cases, but I did not bother. – Leonid Shifrin Mar 14 '12 at 16:55
• @vucko I didn't forget about that, but you didn't indicate what you want to do with that situation, so I assumed it can't happen. There are several possibilities. Can you explain (in the question) what you want to do with that last blank? – Szabolcs Mar 14 '12 at 18:43
• @Szabolcs I don't have any specific request. I just wanted to leave here a note about something that wasn't directly mentioned in the answers. – VLC Mar 14 '12 at 19:53

Lazy people's slow but simple solution:

data //. {s___, "", next_?NumericQ, e___} :> {s, next, next, e}

list = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", 300.348, 293.108, 285.86, 278.599, 271.39};


Yet another way :

list //. {x___, PatternSequence["", c_?NumericQ], y___} -> {x, c, c, y}

 list =
{"", "", 3.82, "", 2.17, 2.38, "", "", 4.54, "", "", 3.97, "", 3.72,
4.75, "", "", "", "", 2.74, "", "", 4.98, 2.40, 3.72, "", 4.5, 4.75, 1., ""};

Quiet@Normal[TemporalData[list /. "" :> Missing[],
MissingDataMethod -> {"Interpolation", InterpolationOrder -> 0}]][[1, All, 2]]


{3.82, 3.82, 3.82, 3.82, 2.17, 2.38, 2.38, 2.38, 4.54, 4.54, 4.54, 3.97, 3.97, 3.72, 4.75, 4.75, 4.75, 4.75, 4.75, 2.74, 2.74, 2.74, 4.98, 2.4, 3.72, 3.72, 4.5, 4.75, 1., 1.}

Here is a variation of Leonid's method that is somewhat faster:

Join @@ Map[Last@# ~ConstantArray~ Length@# &, Split[list, ! NumericQ@# &]]


Timings:

list = Append[RandomReal[5, 300000] /. a_ /; a < 2 :> "", 1.];

Flatten@Map[Replace[#, _ -> Last@#, {1}] &,
Split[list, ! NumericQ@# &]]; // AbsoluteTiming

Join @@ Map[Last@# ~ConstantArray~ Length@# &,
Split[list, ! NumericQ@# &]]; // AbsoluteTiming

{0.4180239, Null}

{0.3080176, Null}