2
$\begingroup$

Suppose you have a list, with each element an ordered pair {a,b} We want to create a new list where each element {a,b} is replaced by {a+b,a-b}

If the original list has three or more ordered pairs, the following works:

list1 = {{a, b}, {c, d}, {e, f}}; (* This list has three ordered pairs *)

list1 /. {x_, y_} -> {x + y, x - y}

The output is, as expected: {{a + b, a - b}, {c + d, c - d}, {e + f, e - f}}

However, if the list has ONLY TWO ordered pairs, the above procedure doesn't seem to work, as shown below:

list2 = {{a, b}, {c, d}}; (* This list has ONLY TWO ordered pairs *)

list2 /. {x_, y_} -> {x + y, x - y}

The output is, unexpectedly(?) {{a + c, b + d}, {a - c, b - d}} Can someone please tell me why this doesn't work? I would appreciate any insight.

I know I can do something like the following to get the desired result:

Cases[list2, {x_, y_} -> {x + y, x - y}]

Thank you very much!

$\endgroup$
3
  • 4
    $\begingroup$ Not a bug. Use Replace[list1, {x_, y_} -> {x + y, x - y}, {1}] for what you're after. $\endgroup$
    – ciao
    Commented Dec 12, 2020 at 5:59
  • 1
    $\begingroup$ if you have to use ReplaceAll, try list2 /. {Except[_List, x_], y_} :> {x + y, x - y}. $\endgroup$
    – kglr
    Commented Dec 12, 2020 at 6:20
  • $\begingroup$ Thank you very much for your input. I understand it now! $\endgroup$
    – user6009
    Commented Dec 12, 2020 at 15:37

2 Answers 2

6
$\begingroup$

ReplaceAll scans the expression starting with the outermost level, working its way inwards.

Therefore, in your example, x_ will match {a,b} and y_ will match {c,d}.

This is an extremely common mistake, and it is why I never use ReplaceAll to process a list of elements. Use Replace instead, and indicate that it should only work at level {1}, i.e. process the elements of the list one-by-one.

Replace[list1, {x_, y_} -> {x + y, x - y}, {1}]
$\endgroup$
1
  • $\begingroup$ Thank you very much for your input. I understand it now! $\endgroup$
    – user6009
    Commented Dec 12, 2020 at 15:38
3
$\begingroup$

Another way to do it:

x = π;
list1 = {{{a, b}, {c, d}}, {e, f}}; (* non-rectangular array *)
list2 = {{a, b}, {c, d}};
list3 = {{a, b}};
list4 = {a, b};

list1 /. {x_, y_}?VectorQ :> {x + y, x - y}
list2 /. {x_, y_}?VectorQ :> {x + y, x - y}
list3 /. {x_, y_}?VectorQ :> {x + y, x - y}
list4 /. {x_, y_}?VectorQ :> {x + y, x - y}

Note the use of :> instead of -> is required, since x has a value.

$\endgroup$

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