Skip to main content

list manipulation - How to repeat the nonblank string?


As the title, if I have a list:


{"", "", "", "2$70", ""}

I will expect:



{"", "", "", "2$70", "2$70"}

If I have


{"", "", "", "3$71", "", "2$72", ""}

then:


{"", "", "", "3$71", "3$71", "2$72", "2$72"}

And


{"", "", "", "3$71", "","", "2$72", ""}


should give


{"", "", "", "3$71", "3$71", "", "2$72", "2$72"}

This is my try:


{"", "", "", "2$70", ""} /. {p : Except["", String], ""} :> {p, p}

But I don't know why it doesn't work. Poor ability of pattern match. Can anybody give some advice?



Answer



As I presently interpret the question



(Now with refinements after considering Chris Degnen's simultaneous answer)


fn[list_] :=
Partition[list, 2, 1, -1, ""] // Cases[{p_, ""} | {_, p_} :> p]

Test:


 {"", "x", "y", "", "z", ""} // fn


{"", "x", "y", "y", "z", "z"}


Patterns


Since you seem only to be interested in a pattern-matching solution here is my proposal to avoid the extremely slow use of ReplaceRepeated while still using pattern-matching as the core of the operation.


fn2[list_] :=
list // ReplacePart @
ReplaceList[list, {a___, p_, "", ___} :> (2 + Length@{a} -> p)]

Recursive replacement


I just realized that this is a perfect time to use a self-referential replacement:


fn3[list_] :=
list /. {a___, p_, "", b___} :> {a, p, p, ##& @@ fn3@{b}}


Benchmark


All three methods are much faster than kglr's foo (note the log-log scale).


Now with Carl Woll's fc, the fastest method yet. ( but no patterns ;-) )


Needs["GeneralUtilities`"]

$RecursionLimit = 1*^5;

BenchmarkPlot[{foo, fn, fn2, fn3, fc},
RandomChoice[{"", "", "", "a", "b"}, #] &

]

enter image description here


Comments