8
$\begingroup$

I do not want to change all of them just some of them in particular rule.

For example the list is given a={1,2,3,4,5,6,7,8,9....,100}

If the number is bigger than 5, the number should be added 1.

a' = {*1,2,3,4,5*,**7,8,9,10,...,101**}

I tried

 Replace[i,i-> i + 1]

or

For[i=6,i<102,i++]

but they didn't work. Please help me.

$\endgroup$
6
  • 1
    $\begingroup$ Try ReplaceAll together with Condition (short forms /. and /;) : a /. x_ /; x>5 :>x+1. $\endgroup$
    – jjc385
    Commented Apr 29, 2017 at 8:55
  • 2
    $\begingroup$ @jjc385 That 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. $\endgroup$
    – Szabolcs
    Commented Apr 30, 2017 at 9:36
  • $\begingroup$ @Szabolcs Point taken. It's a shame that the /. syntax being so much more convenient than e.g. //Replace[#, rule, 1]& provides such a disincentive to do things the proper way. $\endgroup$
    – jjc385
    Commented Apr 30, 2017 at 10:45
  • $\begingroup$ @Szabolcs At times I even find myself wishing the /. (and //.) syntax sugar didn't exist, particularly when refactoring code from replacement over lists to replacement over associations (i.e., their values). $\endgroup$
    – jjc385
    Commented Apr 30, 2017 at 10:45
  • 1
    $\begingroup$ @jjc385 I don't have an issue with 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$
    – Szabolcs
    Commented Apr 30, 2017 at 15:24

10 Answers 10

7
$\begingroup$
Replace[Range @ 100, i_ /; i > 5 -> i + 1, 1]
$\endgroup$
6
$\begingroup$

Some ways (with acknowledgement Kuba):

UnitStep[a - 6] + a
a /. {x_?(# > 5 &) :> x + 1}

f[x_] := x + 1 /; x > 5
f[x_] := x
f /@ a

a + (Boole[# > 5] & /@ a)
$\endgroup$
6
$\begingroup$

There are many solutions here, but I find none of them (except the one by @garej) particularly straightforward or beginner friendly.

If the number is bigger than 5, the number should be added 1.

Use If then, and write a function which performs this transformation:

transformNumber[n_] := If[n > 5, n + 1, n]

Then test the function on individual inputs and make sure that it does what you want it to do:

transformNumber[4]
(* 4 *)

transformNumber[5]
(* 5 *)

transformNumber[6]
(* 7 *)

How do you transform each element in a list? Use Map:

transformNumber /@ a

transformNumber /@ Range[10]
(* {1, 2, 3, 4, 5, 7, 8, 9, 10, 11} *)

Looking at your use of Replace and For, it seems that you are guessing blindly, without any understanding of what these functions do. Experimentation is useful when learning to program, but blind random guessing is not. I recommend you go through some basic tutorials first, and look up any functions you are trying to use in the documentation: Replace, For. But if you are a beginner, it is better to learn Do before starting to use For.

$\endgroup$
1
  • $\begingroup$ +1 for the advice on experimentation for beginners. $\endgroup$
    – jjc385
    Commented Apr 30, 2017 at 15:23
6
$\begingroup$

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 ]
$\endgroup$
2
  • 1
    $\begingroup$ @tomd I'd say your comment, while technically correct, is a bit misleading. ReplacePart works completely differently from Replace and friends. In particular, the rule supplied to ReplacePart is applied to the index of each subpart rather than that subpart's value. Example: ReplacePart[{97, 98, 99}, x_ :> x] returns {1,2,3}. $\endgroup$
    – jjc385
    Commented Apr 30, 2017 at 17:49
  • $\begingroup$ You are of course absolutely correct. I have deleted the comment. I was aware of this (see here) but I do not use Mma much these days (limited access), unfortunately. (ReplacePart[#, 3 -> 10 #[[3]]] & /@ ConstantArray[20, {3, 3}], for example) $\endgroup$
    – user1066
    Commented May 1, 2017 at 7:47
4
$\begingroup$

also

a = Range[10];
MapAt[# + 1 &, a, Position[a, _?(# > 5 &), 2]];
(* or MapAt[# + 1 &, a, Position[a, x_ /; x > 5, 2]] *)
a

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

$\endgroup$
4
$\begingroup$
a=Range@10;
Join[Select[a, # <= 5 &], Select[a, # > 5 &] + 1]
(*{1, 2, 3, 4, 5, 7, 8, 9, 10, 11}*)
$\endgroup$
3
$\begingroup$
(#[[;; #2]]~Join~Cases[#, x_ /; x > #2 :> x + 1]) &[Range@100, 5]
$\endgroup$
2
$\begingroup$

Since V 11.2 there is TakeList

a = Range[10];

Flatten[TakeList[a, {5, 5}] + {0, 1}]

{1, 2, 3, 4, 5, 7, 8, 9, 10, 11}

Or with ReplaceAt (since V 13.1)

ReplaceAt[a, x_ :> x + 1, {5 ;;}]

{1, 2, 3, 4, 5, 7, 8, 9, 10, 11}

$\endgroup$
2
$\begingroup$

Some more.

With

a = Range[10]

we can use the command Clip as follows:

Clip[#, {-Infinity, 5}, {0, # + 1}] & /@ a

another way using ReplacePart

ReplacePart[#, Position[#, x_ /; x > 5] -> # + 1] & /@ a

and UnitStep

a + (1 - UnitStep[5 - a])

All of the above give

{1, 2, 3, 4, 5, 7, 8, 9, 10, 11}

$\endgroup$
2
$\begingroup$

Using Compile and Table:

f = Compile[{{x, _Integer}}, Table[If[i <= 5, i, i + 1], {i, x}]]

Test:

f@100 // RepeatedTiming

enter image description here

$\endgroup$
2
  • 1
    $\begingroup$ (+1) from me. Nicely done mate! $\endgroup$
    – bmf
    Commented Sep 13, 2023 at 20:26
  • 1
    $\begingroup$ Thanks, mate! It's good to greet you again. $\endgroup$ Commented Sep 13, 2023 at 20:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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