1
$\begingroup$

I have a list of integers; I would like to replace anything of the form $x,y,z,2$ in such a list with $x+1, y+1, 0, 0$. The problem is that the $2$ may appear at the front, or in the first three elements, of the sequence (in which case I want to just pretend that the missing leading elements are zero), so I'm trying to use optional pattern values to deal with that. Here is what I've tried (with a different pattern output just to figure out what is going on)

{0, 1, 1, 2} /. {x___, a_: 0, b_: 0, c_: 0, 2, y___} :> {x, a, b, c}
    {{}, 0, 1, 1} (* this is what I'd expect. x matches to the null string *)
{1, 1, 2} /. {x___, a_: 0, b_: 0, c_: 0, 2, y___} :> {x, a, b, c}
    {{}, 1, 1, 0} (* I would have expected a=0 and b=c=1 *)
{1, 2} /. {x___, a_: 0, b_: 0, c_: 0, 2, y___} :> {{x}, a, b, c}
    {{}, 1, 0, 0} (* I would have expected a=b=0, c=1 *)
{2} /. {x___, a_: 0, b_: 0, c_: 0, 2, y___} :> {{x}, a, b, c}
    {{}, 0, 0, 0} (* This matched as I would expect *)

Clearly I'm misunderstanding how this pattern works. Can someone enlighten me?

I would really like to know not only what the right way to do this is, but also why what I tried did not work. I've read the section in Shifrin's book on patterns; are there other good resources to understand how patterns work?

$\endgroup$
  • $\begingroup$ The patterns are doing exactly what they should. It's not clear what you're trying to do. Is it that you have some sequence of integers that can be length 1 to length N, and within that sequence, if the sub-sequence x_,y_,z_,2 is found, it is to be replaced by x+1,y+1,0,0 for all such sub-sequences? And if a 2 occurs before the 4th position is the list to be grown to the left, or the replacement truncated? What about overlaps, e.g. 1,3,4,2,1,2,3,4 - how are those to be handled? I think the OP needs more details... $\endgroup$ – ciao Mar 30 '15 at 23:55
  • $\begingroup$ @rasher I meant for the list to be grown to the left; sorry, I thought that was clear. As for overlaps, it turns out in my application that they don't matter --- that is, whether they are done sequentially or simultaneously you will eventually get the same result (I am intending to use ReplaceAll once I get this working). $\endgroup$ – rogerl Mar 31 '15 at 12:27
2
$\begingroup$

The misunderstanding as far as I can tell lies in the order in which missing patterns are filled when using Optional (pattern : value). Why does Mathematica fill the missing items from left to right rather than right to left?

It becomes quite clear if you think about how Optional is meant to be used. In Mathematica Optional is used to provide default values for function arguments:

f[x_: 0, y_: 0, z_: 0] := {z, y, z}
f // DownValues

{HoldPattern[f[x_ : 0, y_ : 0, z_ : 0]] :> {x, y, z}}

DownValues shows us how Mathematica represents a function - a function in Mathematica is nothing but a rule. You can imagine replacing f with List ({}) in which case this function is very similar to your rule. Now imagine that if you wrote f[1,2] this would result in {0,1,2} - this would be counterintuitive to most people. We've left out not the first argument but the last, i.e. we expect Mathematica to use the provided arguments to fill in the blanks from left to right, not right to left.

I suggest using several patterns to solve your problem:

rules = {
   {x___, a_, b_, c_, 2, y___} :> {x, a, b, c},
   {b_, c_, 2, y___} :> {0, b, c},
   {c_, 2, y___} :> {0, 0, c},
   {2, y___} :> {0, 0, 0}
   };
{0, 1, 1, 2} /. rules
(* {0, 1, 1} *)
{1, 1, 2} /. rules
(* {0, 1, 1} *)
{1, 2} /. rules
(* {0, 0, 1} *)
$\endgroup$
  • $\begingroup$ I think there are some typos in your post - check your example and results... $\endgroup$ – ciao Mar 31 '15 at 0:00
  • $\begingroup$ @rasher yes, thanks. I only found one typo so if you see any more please elaborate. $\endgroup$ – C. E. Mar 31 '15 at 0:04
  • $\begingroup$ I understand your point about functions being represented as rules. But is there a reason other than "we chose to do it that way" for filling from right to left, which is to me counterintuitive? I thought about using multiple rules, but figured there had to be a better way. $\endgroup$ – rogerl Mar 31 '15 at 12:23
  • $\begingroup$ @rasher Oh, I see. It's totally the way you'd expect it to work for functions. $\endgroup$ – rogerl Mar 31 '15 at 12:29

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.