13
$\begingroup$

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?

$\endgroup$
  • 4
    $\begingroup$ What should happen when the first element is a zero? $\endgroup$ – Sjoerd Smit Sep 25 at 14:53
15
$\begingroup$

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}

$\endgroup$
  • 1
    $\begingroup$ 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! $\endgroup$ – Jonathan Kinlay Sep 25 at 22:41
  • $\begingroup$ What sort of (Mathematica) black magic is this!? My +1 sir. $\endgroup$ – Rebel-Scum Sep 27 at 13:54
9
$\begingroup$

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} *)
$\endgroup$
  • $\begingroup$ This must be the fastest (and simplest) of the lot. The one I knew existed, but never reached. $\endgroup$ – Suba Thomas Sep 26 at 22:19
7
$\begingroup$

Perhaps something like this will appeal

l //. {{a___, 1, 0, b___} -> {a, 1, 1, b}, {a___, -1, 0, b___} -> {a, -1, -1, b}}
$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Jonathan Kinlay Sep 25 at 22:35
5
$\begingroup$

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.

$\endgroup$
3
$\begingroup$

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}

$\endgroup$
-2
$\begingroup$

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?

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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