14
$\begingroup$

I noticed that "ReplacePart" can use pattern. For example:

ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_, i_} -> x]
{{x, 0, 0}, {0, x, 0}, {0, 0, x}}

So I naively think I can do a little change like

ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_+1, i_} -> x]

But it gives

{x, x, x}

Why? I anticipated that the result whould be

{{0, 0, 0}, {x,0,0}, {0, x, 0}}

Can anyone help?

$\endgroup$
1
  • $\begingroup$ I think you may have found a bug in ReplacePart. $\endgroup$
    – m_goldberg
    Mar 6, 2013 at 15:27

3 Answers 3

13
$\begingroup$

Use a Condition (/;) to check the relation between the values of the pattern elements. You must also use RuleDelayed (:>) instead of Rule (->), since the rule now depends on the particular values of the matched pattern.

ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_, j_} :> 
  x /; i == j + 1]
(* {{0, 0, 0}, {x, 0, 0}, {0, x, 0}} *)

UPDATE: The erroneous-appearing result of the original code appears to be due to ReplacePart checking the second argument to see if it is a list of parts to be replaced. If the first element of the list has depth (e.g. {1} or _+1), then ReplacePart treats all elements of the list as parts to be replaced.

Consider:

(* Expected use *)
ReplacePart[Array[f, {3, 3}], {{1}, {2}, {0}} -> x]
(* x[x, x, {f[3, 1], f[3, 2], f[3, 3]}] *)

(* First element is nonsense *)
ReplacePart[Array[f, {3, 3}], {_+1, 1, 2, 0} -> x]
(* x[x, x, {f[3, 1], f[3, 2], f[3, 3]}] *)

(* First element doesn't exist *)
ReplacePart[Array[f, {3, 3}], {{7}, 1, 2, 0} -> x]
(* x[x, x, {f[3, 1], f[3, 2], f[3, 3]}] *)

SECOND EDIT: So to analyze the original case, the first element of the replacement-part list has nontrivial depth, so we treat each element as a part to be replaced. The first element is nonsense, so it matches nothing. The second element is a Blank, so it matches all integers and all parts of the list are replaced by x.

$\endgroup$
7
  • 2
    $\begingroup$ can you also explain why the op got {x,x,x} in his approach? I can't make sense of that return value... $\endgroup$ Mar 6, 2013 at 9:41
  • $\begingroup$ +1 although I think you don't necessarily need a delayed rule here as long as you constrain the pattern appropriately: ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_, j_} /; (i == j + 1) -> x]. $\endgroup$
    – gpap
    Mar 6, 2013 at 12:58
  • $\begingroup$ @Mr.Wizard So what about this: ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_, i_ + 1} -> x] gives {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}. Can I understand it as when Mathematica scan the pattern list towards i_+1, and find that it is neither a pattern nor the first element, So Mathematica just quit and do nothing?? $\endgroup$
    – matheorem
    Mar 7, 2013 at 11:24
  • $\begingroup$ @matheorem ReplacePart examines the first item, which has trivial depth; therefore, it treats the list as a single position to be replaced. At least one element of the list is nonsense, therefore nothing is matched and nothing is replaced. $\endgroup$
    – Xerxes
    Mar 7, 2013 at 18:21
  • $\begingroup$ @Xerxes then what about ReplacePart[{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, {i_ + 1, i_, i_} -> x], it gives {x, x, x} . Ignoring the first nonsense element, the pattern shoud read as {i_,i_}->x, right? If so the result is unreasonable. $\endgroup$
    – matheorem
    Mar 8, 2013 at 0:13
6
$\begingroup$

I think a possible explanation is that when an element of the part specification passes some preliminary test but then fails to resolve to something meaningful it is removed from the list mid-process. For example:

m = Range@9 ~Partition~ 3;
r = {1, 2, 3};
x =.

ReplacePart[m, {i_ + 1, #} -> x] & /@ r // Column
ReplacePart[m, {_ + "bad", #} -> x] & /@ r // Column

Mathematica graphics
Mathematica graphics

Which is the same behavior as:

ReplacePart[m, {#} -> x] & /@ r // Column

Mathematica graphics

If the first element of the specification does not contain a pattern nothing is replaced:

ReplacePart[m, {"bad", #} -> x] & /@ r // Column

Mathematica graphics

$\endgroup$
2
$\begingroup$

I brought this to the attention of WRI's tech support. This is their response:

This behavior is due to the way ReplacePart processes the part position specifications given to it. When a part position specification cannot structurally match a part position, behavior of ReplacePart is technically undefined, though the proposed explanation at the MSE post to which you implicitly refer is roughly accurate. In this case, ReplacePart does end up treating each part position spec as an entire part spec due to the ambiguity of the first part position spec.

To avoid behavior like this, you can simply use Condition (/;) to enforce relationships between part position specs.

On your behalf, I've filed a suggestion with our development team to improve documentation on this aspect of ReplacePart behavior.

It nice to know that they are looking-in at what goes on here and that they accept Mr. Wizards analysis as "roughly accurate".

$\endgroup$

Your Answer

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

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