5
$\begingroup$

I have the following list:

input = {{0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 
   0, 1}, {0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
    0, 1}, {1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 
   1, 0, 1}}

there are two conditions:

  • When a '0' is followed by '1', the value of '0' change to .5
  • When a '1' is followed by '0', the value of '0' change to .5

the desired output is:

output = [{{0, 0, 0, .5, 1, 1, 1, .5, 1, .5, 0, .5, 1, 1, .5, 1, .5, 
    0, .5, 1, .5, 1}, {.5, 1, .5, 1, .5, .5, 1, .5, 0, 0, 0, .5, 1, 
    1, .5, 1, .5, 0, .5, 1, .5, 1}, {1, 1, .5, .5, 1, 1, 1, .5, 0, 0, 
    0, .5, 1, 1, .5, 1, 0, 0, .5, 1, .5, 1}}]

Who has a suggestion how to get the desired output

$\endgroup$
  • 2
    $\begingroup$ should desired[[3]] be {1, 1, 0.5, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}? $\endgroup$ – user1066 Aug 15 at 14:28
8
$\begingroup$

Using ReplaceRepeated (//.) and pattern matching:

input //. {{x___, 0, 1, y___} :> {x, 0.5, 1, y}, {x___, 1, 0, y___} :> {x, 1, 0.5, y}}

{{0, 0, 0, 0.5, 1, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}, {0.5, 1, 0.5, 1, 0.5, 0.5, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}, {1, 1, 0.5, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}}

Note that there is a slight difference between this and your suggested output, highlighted in bold. As @Nasser received this result by his method as well, I suspect that the original suggested output was in error.

$\endgroup$
  • $\begingroup$ Tricky. I tried it similar inside Cases but only one substitution is made. What could be the reason? Thanks! $\endgroup$ – Ulrich Neumann Aug 15 at 14:08
  • 1
    $\begingroup$ /. only tries to replace once per complete match, as I understand, so since each list matches {x___, 1, 0, y___} or the other it only undergoes one substitution each. //. explicitly retries until no matches remain. I think Cases works more like /. in that respect. $\endgroup$ – eyorble Aug 15 at 14:12
  • $\begingroup$ Thanks, I have to think about it. $\endgroup$ – Ulrich Neumann Aug 15 at 14:17
8
$\begingroup$

You can also use a combination of SequenceReplace and FixedPoint:

f = Map[SequenceReplace[{{0, 1} -> Sequence[.5, 1], {1, 0} -> Sequence[1, .5]}]], 

FixedPoint[f, input]

{{0, 0, 0, 0.5, 1, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1},
{0.5, 1, 0.5, 1, 0.5, 0.5, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1},
{1, 1, 0.5, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}}

You can also use Nest in place of FixedPoint:

Nest[f , input, 2] == %

True

$\endgroup$
4
$\begingroup$

For a rewriting problem, use rewriting explicitly:

input //. {
    {x___, 0, 1, y___} -> {x, 0.5, 1, y}, 
    {x___, 1, 0, y___} -> {x, 1, 0.5, y}
}
(*
    {{0, 0, 0, 0.5, 1, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}, 
    {0.5, 1, 0.5, 1, 0.5, 0.5, 1, 0.5, 0, 0, 0, 0.5, 1,1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}, 
    {1, 1, 0.5, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}}
*)
$\endgroup$
1
$\begingroup$

This is not a "functional" way to do it. But an old fashioned loop and few if's. But it gives the result you show

foo[input_List] := Module[{n, i, current, next, before},
  n = Length[input];

  (*handle edge cases*)
  If[n == 1, Return[input, Module]];
  If[n == 2, 
   Return[If[input[[1]] == 0 && input[[2]] == 1, {0.5, 1}, 
     If[input[[2]] == 0 && input[[1]] == 1, {1, 0.5}, input]], 
    Module]];

  (*general case for list of length \[GreaterEqual] 3*)
  Table[
   current = input[[i]];
   If[i == 1,
    If[input[[i]] == 0 && input[[i + 1]] == 1, 0.5, input[[i]]]
    ,
    If[i == n, 
     If[input[[n]] == 0 && input[[n - 1]] == 1, 0.5, input[[n]]]
     ,
     before = input[[i - 1]]; 
     next = input[[i + 1]];
     If[current == 0 && next == 1, 0.5, 
      If[current == 0 && before == 1, 0.5, current]]
     ]
    ],
   {i, 1, Length[input]}
   ]
  ]


input = {{0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 
    0, 1}, {0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 
    1, 0, 1}, {1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 
    0, 1, 0, 1}};

Now map foo on the input

 result = foo[#] & /@ input

gives

{{0, 0, 0, 0.5, 1, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 
  0.5, 1, 0.5, 1}, {0.5, 1, 0.5, 1, 0.5, 0.5, 1, 0.5, 0, 0, 0, 0.5, 1,
   1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}, {1, 1, 0.5, 0.5, 1, 1, 1, 0.5, 
  0, 0, 0, 0.5, 1, 1, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 1}}

I suspect there might be a shorter way to do this if one works harder on it.

$\endgroup$

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.