ReplaceAt¶
Status: Stable
documented, exercised by the test suite and/or worked examples, with no known limitations recorded.
Description¶
ReplaceAt[expr, rules, n]
transforms expr by replacing the n-th element using rules.
ReplaceAt[expr, rules, {i, j, ...}]
replaces the part of expr at position {i, j, ...}.
ReplaceAt[expr, rules, {{i1, j1, ...}, {i2, j2, ...}, ...}]
replaces parts at several positions.
Notes
Rules may be a single Rule/RuleDelayed or a list of them; rules are tried in order and the first match wins. Negative indices count from the end; 0 targets the head. All and Span specifications are supported. On an association a position is a key, Key\[k\], or a positional index over the entries, and the rules are tried against the value. Repeated positions cause rules to be applied repeatedly to that part. ReplaceAt\[expr, rules, {}\] is an empty list of positions and replaces nothing, while {{}} is the position of expr itself. A position that does not exist leaves ReplaceAt unevaluated.Examples (22)¶
Every input below was run against the current Mathilda build and its output recorded.
Basic examples (17)¶
In[1]:= ReplaceAt[{a, a, a, a}, a -> xx, 2]
Out[1]= {a, xx, a, a}
In[2]:= ReplaceAt[{a, a, a, a}, a -> xx, {{1}, {4}}]
Out[2]= {xx, a, a, xx}
In[3]:= ReplaceAt[{{a, a}, {a, a}}, a -> xx, {2, 1}]
Out[3]= {{a, a}, {xx, a}}
In[4]:= ReplaceAt[{a, a, a, a}, a -> xx, -2]
Out[4]= {a, a, xx, a}
In[5]:= ReplaceAt[{{a, a, a}, {a, a, a}}, a -> xx, {-1, -2}]
Out[5]= {{a, a, a}, {a, xx, a}}
In[6]:= ReplaceAt[{1, 2, 3, 4}, x_ :> 2 x - 1, {{2}, {4}}]
Out[6]= {1, 3, 3, 7}
In[7]:= ReplaceAt[{a, b, c, d}, {a -> xx, _ -> yy}, {{1}, {2}, {4}}]
Out[7]= {xx, yy, c, yy}
In[8]:= ReplaceAt[{{a, a}, {a, a}}, a -> xx, {All, 2}]
Out[8]= {{a, xx}, {a, xx}}
In[9]:= ReplaceAt[{{a, b}, {c, d}, e}, x_ :> f[x], 2]
Out[9]= {{a, b}, f[{c, d}], e}
In[10]:= ReplaceAt[{{a, b}, {c, d}, e}, x_ :> f[x], -1]
Out[10]= {{a, b}, {c, d}, f[e]}
In[11]:= ReplaceAt[{{a, b}, {c, d}, e}, x_ :> f[x], {2, 1}]
Out[11]= {{a, b}, {f[c], d}, e}
In[12]:= ReplaceAt[{{a, b}, {c, d}, e}, x_ :> f[x], {{1}, {3}}]
Out[12]= {f[{a, b}], {c, d}, f[e]}
In[13]:= ReplaceAt[{{a, b}, {c, d}, e}, x_ :> f[x], {{1, 2}, {2, 2}, {3}}]
Out[13]= {{a, f[b]}, {c, f[d]}, f[e]}
In[14]:= ReplaceAt[{a, a, a, a, a}, a -> xx, 2 ;; 4]
Out[14]= {a, xx, xx, xx, a}
In[15]:= ReplaceAt[a + b + c + d, _ -> x, 2]
Out[15]= a + c + d + x
In[16]:= ReplaceAt[x^2 + y^2, _ -> z, {{1, 1}, {2, 1}}]
Out[16]= 2 z^2
In[17]:= ReplaceAt[{a, b, c}, _ -> f, 0]
Out[17]= f[a, b, c]
Applications (5)¶
In[18]:= ReplaceAt[{a, b, c, d}, x_ -> X, 2]
Out[18]= {a, X, c, d}
In[19]:= ReplaceAt[{a, b, c, d}, x_ -> X, -1]
Out[19]= {a, b, c, X}
In[20]:= ReplaceAt[{{a, b}, {c, d}}, x_ -> X, {2, 1}]
Out[20]= {{a, b}, {X, d}}
In[21]:= ReplaceAt[1 + x + x^2 + x^3, e_ :> D[e, x], {2}]
Out[21]= 2 + x^2 + x^3
In[22]:= ReplaceAt[{1, 2, 3, 4, 5}, n_ :> n^2, {2 ;; 4}]
Out[22]= {1, 4, 9, 16, 5}
Implementation notes¶
Algorithm. builtin_replace_at (src/replace.c) applies rules at one or more explicit positions rather than by structural matching everywhere. It parses the rule(s) with parse_replace_rules into a ReplaceRule[], then disambiguates the position argument: a non-empty List whose first element is itself a List is a list of paths (applied sequentially, repeated positions re-apply the rules); otherwise it is a single path (a bare index or a List of indices). Navigation is replaceat_at_path, which consumes one index per level: index 0 descends into the head, a positive/negative integer selects an argument (negative counts from the end), All recurses into every argument, and a Span[start, stop, step] walks a strided slice. When the path is exhausted at a node, the rules are matched against that node only via the same match/replace_bindings machinery used by Replace/ReplaceAll; the first matching rule's bound replacement is substituted. Sub-trees off the targeted path are deep-copied unchanged.
Data structures. ReplaceRule[] (borrowed pattern/replacement pointers); the path is an Expr** slice advanced by pointer arithmetic (path + 1, plen - 1) as the recursion descends.
Protected.rulesmay be a singleRule(->),RuleDelayed(:>), or a list of such rules. The rules are tried in order; the first one that applies wins. If no rule matches at a targeted position, the part is left unchanged.- For
RuleDelayed, the right-hand side is evaluated separately for each match after substituting bound pattern variables. - Negative integer indices count from the end. The literal index
0targets the head of an expression. - Path components may be integers, the symbol
All(selects every child at that level), orSpanexpressions such asi ;; jori ;; j ;; k(includingUpTo[n]bounds). - Works on expressions with any head (not just
List); after substitution the evaluator re-applies canonical ordering forOrderlessheads such asPlusandTimes. - On an
Associationa position is a key,Key[k], or a positional index over the entries, and the rules are tried against the value;All,Spanand0work there too. - The position list uses the same form as is returned by
Position.ReplaceAt[expr, rules, {}]is an empty list of positions and replaces nothing; the position of the whole expression is the empty path,{{}}. - A position that does not exist ā an out-of-range index, an absent key, a malformed
Span, or a path that runs into an atom ā leavesReplaceAtunevaluated, asPartdoes for{a, b, c}[[99]]. - Position resolution is shared with
MapAtvia one walker (expr_apply_at_path,src/part.c), so the two agree on every position spec by construction.
Attributes: Protected.
References¶
See also: ReplaceAll, Rule, RuleDelayed, Span, List, Orderless, Plus, Times
- Source:
src/replace.c - Specification:
docs/spec/builtins/assignment-and-rules.md - Tests:
tests/test_replaceat.c
Notes & additional examples¶
Notes¶
ReplaceAt applies rules only at explicitly named positions, leaving the rest
of the expression untouched. Positions may be a single index, a part list
{i, j, ...}, a list of positions, All, or a Span. Negative indices count
from the end and 0 targets the head. Because the rule sees the part as a
whole expression, position-targeted rewrites can do real work: applying
e_ :> D[e, x] at part {2} of 1 + x + x^2 + x^3 differentiates just that
one summand (here the x term, whose derivative 1 merges into the leading
constant), while n_ :> n^2 over the span 2 ;; 4 squares a contiguous slice.