# Replace zeros in a list with last nonzero value

This question is closely related to the problem of zero crossings.

Suppose I have a list l = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1}

and I want to replace the zeros with the previous nonzero value, like this:

{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

A rather clunky way to do this is with:

  f = TimeSeries[l /. 0 -> Missing[],
MissingDataMethod -> {"Interpolation", InterpolationOrder -> 0}]


Then indeed f[-1 + Range@Length@l]gives the required result.

However, there must be a more elegant way to achieve same, with patterns.

Can anyone supply a suggestion?

• What should happen when the first element is a zero? – Sjoerd Smit Sep 25 at 14:53

### SequenceReplace

SequenceReplace[ p:{a_, 0..} :> Sequence @@ (p /. 0 -> a)] @ l


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

or

FixedPoint[SequenceReplace[{a_, 0} :> Sequence[a, a]], l]


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

### ReplaceRepeated

An alternative way to use ReplaceRepeated with a single replacement rule:

l //. {a___, b_, 0, c___} :> {a, b, b, c}


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

### Memoization

Memoize the last non-zero value (inspired by @WReach's answer):

f[x_] := (f[0] = x; x)
f /@ l


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

### Split + ReplaceAll

Split[l, #2 == 0 &] /. p : {a_, 0 ..} :> (p /. 0 -> a) // Flatten


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

### TimeSeries + MissingDataMethod

Using the "Values" property with OP's f:

f["Values"]


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

• One of the reasons I asked this question even though I had a working (although inelegant) solution was to see all the creative ways in which MMA experts are able to use the Wolfram language to solve a problem. Outstanding! – Jonathan Kinlay Sep 25 at 22:41
• What sort of (Mathematica) black magic is this!? My +1 sir. – Rebel-Scum Sep 27 at 13:54

Define a simple function, using FoldList

op = FoldList[If[#2 == 0, #1, #2] &];

l = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1};

op@l
(* {-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1} *)

• This must be the fastest (and simplest) of the lot. The one I knew existed, but never reached. – Suba Thomas Sep 26 at 22:19

Perhaps something like this will appeal

l //. {{a___, 1, 0, b___} -> {a, 1, 1, b}, {a___, -1, 0, b___} -> {a, -1, -1, b}}

• This is the kind of thing I was aiming for, but I couldn't find the right formulation. I find patterns such a challenge (although I do use them extensively). Anyway that you for a great solution. – Jonathan Kinlay Sep 25 at 22:35

Given:

list = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1}


Then:

Module[{prev = 0}, Replace[list, {0 :> prev, x_ :> (prev = x)}, {1}]]

(* {-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1} *)


The initial value assigned by prev = 0 is only used for lists that start with a zero -- choose another value if desired.

A few more...

l = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1};

Do[If[l[[i]] == 0, l[[i]] = l[[i - 1]]], {i, 2, Length[l]}]

l


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

fn[l_] := Block[{l1 = l},
Set[Part[l1, #[[2]]], Part[l1, #[[1]]]] & /@ SequencePosition[l, {_, 0}];
l1
]

l = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1};

FixedPoint[fn, l]


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

l = {-1, -1, 0, 1, 0, 0, -1, -1, 1, 1, 1, 0, 0, 0, -1};

Fold[{#1, If[#2 == 0, Last[#1], #2]} &, l[[1 ;; 1]], l[[2 ;; -1]]] //Flatten


{-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1}

The creativity demonstrated by all these solutions is impressive.

Here’s a really tough follow-up challenge. Can anyone write a WL program that will generate the code for any one of these solutions?

• This isn't an answer. It should either be an extension to the question, or a fresh question referring back to the original one. – High Performance Mark Sep 27 at 9:38