Szabolcs response to my comment inspired to me write an answer:
Replace[ a, x_ /; x>5 :> x+1, 1 ]
This is very similar to Garej's answer :
Replace[Range @ 100, i_ /; i > 5 -> i + 1, 1]
(Uses ->
(Rule
) rather than :>
(RuleDelayed
))
It's also similar to my comment :
a /. x_ /; x>5 :> x+1
(Uses /.
(ReplaceAll
) rather than Replace
)
Why use :>
(RuleDelayed
) rather than ->
(Rule
)?
Consider this:
a=Range[10];
x=-99;
ruleDelayedMethod = Replace[ a, x_ /; x>5 :> x+1, 1 ]
{1, 2, 3, 4, 5, 7, 8, 9, 10, 11}
ruleMethod = Replace[ a, x_ /; x>5 -> x+1, 1 ]
{1, 2, 3, 4, 5, -98, -98, -98, -98, -98}
The difference is that the x
on the right hand side (RHS) of :>
refers specifically to the x
which matches the pattern x_
.* (We say that x
is localized on the right hand side of RuleDelayed
but not Rule
.) Mathematica's syntax highlighting nicely supports this: Both x
's in x_ :> x
are colored green, whereas the RHS of x_->x
is colored black.
*In fact, x_
precisely means "a pattern named x
which matches _
, (i.e., any expression)"
Moreover, the right hand side of ->
is evaluated immediately, whereas the right hand side of :>
doesn't evaluate until the rule is actually applied (hence the name RuleDelayed
). You can real more about the difference between Rule
and RuleDelayed
on their respective documentation pages: (Docs for Rule
)(Docs for RuleDelayed
).
This was something which confused me as a new user. In fact, my first question on this site was a now-closed/deleted question about why ->
was failing, when I should have been using :>
.
Why use
Replace
rather than
ReplaceAll
(/.
) ?
ReplaceAll
checks whether various pieces of the expression match the LHS of the rule. Replace
takes a 'level spec' argument which tells you which components of the expression to check. As such,ReplaceAll
is both more efficient and more portable.
To quote Szabolcs' comment
[Using ReplaceAll
] is sloppy because it will also attempt to
transform the whole list, as well as its head. It does work, but only
because things like List > 5
and {1,2,3} > 5
do not evaluate to
True.
As humans, users may favor the simple syntax sugar of /.
over typing out Replace[ ... , 1]
, as I did in my original comment. One may ask whether there's a nice solution to this. One option use a pure function as a postfix operator:
a // Replace[ #, x_ /; x>5 :> x+1, 1 ]&
Another option is to use Map
(/@
), taking advantage of the operator form of Replace
:
Replace[ x_ /; x>5 :> x+1 ] /@ a
or (equivalently)
a // Map@Replace[ x_ /; x>5 :> x+1 ]
Note that the two potential solutions using Map
(/@
) are particularly simple because the replacement occurs at level 1 in the list. Were a deeper level required, the solution using Map
becomes less elegant than simply supplying Replace
with a levelspec as the third argument.
One solution which (1) has a similar look and feel to using the /.
syntactic sugar and (2) scales nicely when a levelspec is required is to define a custom operator form for Replace
which takes a levelspec:
ClearAll[replaceLev]
replaceLev[ rule_, levelspec_ ][ expr_ ] :=
Replace[ expr, rule, levelspec ]
Then one can solve the original post's problem with:
a // replaceLev[ x_ /; x>5 :> x+1, 1 ]
ReplaceAll
together withCondition
(short forms/.
and/;
) :a /. x_ /; x>5 :>x+1
. $\endgroup$List > 5
and{1,2,3} > 5
do not evaluate toTrue
. $\endgroup$/.
syntax being so much more convenient than e.g.//Replace[#, rule, 1]&
provides such a disincentive to do things the proper way. $\endgroup$/.
(and//.
) syntax sugar didn't exist, particularly when refactoring code from replacement over lists to replacement over associations (i.e., their values). $\endgroup$ReplaceAll
in general. I am often sloppy and use it in situations like this (though I prefer to avoid it in package code which needs to be robust). I mentioned this here only because the OP is new to Mathematica. $\endgroup$