# How to replace the arguments of a function?

I have the following type of (very long) expression:

$$\ldots + X[1,2,3,5] + X[2,4,5,6] + \ldots \tag{1}$$

where $$X[a,b,c,d]$$ is some undefined function. I would like to replace all the occurrences of $$5$$ by $$4$$ and $$6$$ by $$5$$ simultaneously in the argument of $$X$$, without having to do the replacements one by one. For the example above I should get:

$$\ldots + X[1,2,3,4] + X[2,4,4,5] + \ldots \tag{2}$$

Any idea how to proceed?

expr = X[1, 2, 3, 5] + X[2, 4, 5, 6]
expr /. {5 -> 4, 6 -> 5}

(* X[1, 2, 3, 4] + X[2, 4, 4, 5] *)


Note that the order of the rules doesn't matter, here; according to the documentation for ReplaceAll (which is the function underlying the /. infix),

ReplaceAll looks at each part of expr, tries all the rules on it, and then goes on to the next part of expr. The first rule that applies to a particular part is used; no further rules are tried on that part or on any of its subparts.

So even if 6 gets replaced by 5 in one part of the expression, Mathematica will not subsequently replace it by 4 because of the presence of the other rule.

EDIT: After I posted the ugly-ass code at the end of this answer, BobHanlon pointed out the much more elegant solution:

expr2 /. X[arg__] :> (X[arg] /. {5 -> 4, 6 -> 5})


I have left the original code below for posterity.

OLD EDIT: If 6 or 5 appears in the long expression, the above code will replace it there as well. If this is undesirable behavior, we need to restrict the action of ReplaceAll to anything inside an X. We can do this by using Position to find the positions of all of the Xs in the expression, and then using MapAt to apply ReplaceAll only to those parts:

expr2 = X[1, 2, 3, 5] + 6 X[2, 4, 5, 6];
xpositions = Most /@ Position[expr2, X];
MapAt[ReplaceAll[ {5 -> 4, 6 -> 5}], expr2, xpositions]

(* X[1, 2, 3, 4] + 6 X[2, 4, 4, 5] *)

• But numbers might also appear in the expression. What if expr = 6*X[2,4,5,6] ?
– Pxx
Commented Sep 30, 2021 at 19:44
• @Pxx: Then you should have included that in the question. ;-) That totally makes sense, though, in retrospect. I'll see what I can figure out that would work and edit this answer appropriately. Commented Sep 30, 2021 at 19:55
• @Pxx: I think I've now got a version that will only replace the arguments of X. Commented Sep 30, 2021 at 20:32
• expr2 /. X[arg__] :> (X[arg] /. {5 -> 4, 6 -> 5}) Commented Sep 30, 2021 at 20:35
• slightly shorter: expr2 /. x_X :> (x /. {5 -> 4, 6 -> 5})
– kglr
Commented Sep 30, 2021 at 22:58