# Replace pattern with the number of matches so far

I want to replace a n-th pattern match in an expression with n. This is a very simple task, though it appears very hard to find an elegant implementation.

For example, with input

inp = {x, y, z, x, y, x, x, z}


I wish to compute, replacing pattern x,

{1, y, z, 2, y, 3, 4, z}


Preferably, I'd like to access the index n in the replacement rule. E.g. something like

Func[inp, x :> Symbol[m<>ToString@#]& ]

>>> {m1, y, z, m2, y, m3, m4, z}


How can I achieve this? It's trivial using Count and a For loop, but is very un-stylistic.

Consider using the Increment operator:

(*In[1]:= *)i = 1;

(*In[2]:= *)inp = {x, y, z, x, y, x, x, z};

(*In[3]:= *)inp /. x :> i++

(*Out[3]= {1, y, z, 2, y, 3, 4, z}*)


Hopefully it's obvious how this can be extended to your example using Symbol.

• If you start with i=0 and then use inp /. x :> ++i, then at the end the index i contains the number of elements matched (instead of one more). Also, if you use inp /. x :> m[++i], then you get an indexing as desired (but without using Symbol, which may not be necessary). Commented Jan 30, 2020 at 21:31
• A pity to have to use a variable, but it's still quite concise Commented Jan 31, 2020 at 16:17
• @Roman quite right, m[ind] is much more elegant, thanks! Commented Jan 31, 2020 at 16:18
• @AntiEarth with Block you can make i a local variable, so you don't need to worry about polluting the name space. Commented Jan 31, 2020 at 16:45
inp = {x, y, z, x, y, x, x, z};


Using SubsetMap (new in 12.0)

SubsetMap[Range[Length @ #] &, inp, #] & @ Position[inp, x]


{1, y, z, 2, y, 3, 4, z}

Using ReplacePart

ReplacePart[inp, Thread[# -> Range[Length @ #]] & @ Position[inp, x]]


{1, y, z, 2, y, 3, 4, z}

inp = {x, y, z, x, y, x, x, z};


Using Fold:

func = If[#2 === x, {#1[[1]] + 1, Append[#1[[2]], #1[[1]] + 1]},
{#1[[1]], Append[#1[[2]], #2]}] &;

Fold[func, {0, {}}, inp][[2]]


{1, y, z, 2, y, 3, 4, z}

inp = {x, y, z, x, y, x, x, z};
Accumulate[inp /. {x -> 1, y -> 0, z -> 0}]}] /. {{x, a_} :>
Symbol["m" <> ToString[a]], {a_, _} :> a}


-> {m1, y, z, m2, y, m3, m4, z}

More alternatives that avoid an extra counter variable...

inp = {x, y, z, x, y, x, x, z};


Let MapIndexed manage the state after splitting:

Flatten[MapIndexed[ReplacePart[#1, 1 -> #2] &, SequenceCases[inp, {x, Except[x] ...}]]]


Mix PositionIndex with Position to define replacement rules:

Flatten[ReplacePart[inp, PositionIndex[Position[inp, x]]]]


Use FoldPairList with an accumulator:

FoldPairList[
If[x === #2, {x, 1 + #1}, {#2, #1}] &,
0,
inp,
If[x === #[[1]], #[[2]], #[[1]]] &]

• Your second solution is my favourite so far! Commented Jun 28 at 21:12