11
$\begingroup$

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.

$\endgroup$

6 Answers 6

8
$\begingroup$

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.}
$\endgroup$
7
$\begingroup$

Here is a straightforward linear-time version

Flatten@Map[Replace[#, _ -> Last@#, {1}] &, Split[list, ! NumericQ@# &]]
$\endgroup$
4
  • $\begingroup$ 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. $\endgroup$
    – VLC
    Commented Mar 14, 2012 at 16:52
  • 4
    $\begingroup$ @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. $\endgroup$ Commented Mar 14, 2012 at 16:55
  • $\begingroup$ @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? $\endgroup$
    – Szabolcs
    Commented Mar 14, 2012 at 18:43
  • $\begingroup$ @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. $\endgroup$
    – VLC
    Commented Mar 14, 2012 at 19:53
4
$\begingroup$

Lazy people's slow but simple solution:

data //. {s___, "", next_?NumericQ, e___} :> {s, next, next, e}
$\endgroup$
3
$\begingroup$
list = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
        "", "", "", "", "", "", "", 300.348, 293.108, 285.86, 278.599, 271.39};

Yet another way :

list //. {x___, PatternSequence["", c_?NumericQ], y___} -> {x, c, c, y}
$\endgroup$
3
$\begingroup$
 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.}

$\endgroup$
1
$\begingroup$

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}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.