# A replacement problem

list = {1, x, 3, x, 4, x, x, 3, 4, 3, x, 2, 3, x, 8, 7};


If there is exactly one integer between two x I want to replace it with y:

list //. {a___, x, _Integer, x, b___} :> {a, x, y, x, b}


{1, x, y, x, y, x, x, 3, 4, 3, x, 2, 3, x, 8, 7}

How can I replace one or more integers with y?

Desired result with n = 2:

{1, x, y, x, y, x, x, 3, 4, 3, x, y, y, x, 8, 7}

With n = 3:

{1, x, y, x, y, x, x, y, y, y, x, y, y, x, 8, 7}

Let's try:

list = {1, x, 3, x, 4, x, x, 3, 4, 3, x, 2, 3, x, 8, 7};

list //. {a___, x, s : Repeated[_Integer, 2], x, b___} :>
{a, x, Sequence @@ ConstantArray[y, Length[{s}]], x, b}
(* -> {1, x, y, x, y, x, x, 3, 4, 3, x, y, y, x, 8, 7} *)

list //. {a___, x, s : Repeated[_Integer, 3], x, b___} :>
{a, x, Sequence @@ ConstantArray[y, Length[{s}]], x, b}
(* -> {1, x, y, x, y, x, x, y, y, y, x, y, y, x, 8, 7} *)


Seems to do the job. I'm not sure if it's the most efficient approach.

This is almost a perfect application for the new SequencePosition function, which lets you pick patterns out of lists in a straightforward way. It's made a bit more awkward than necessary by a weird performance issue, but it allows for a solution that is both reasonably elegant and reasonably efficient:

replaceBetween[list_, n_Integer?Positive, sym_Symbol, new_Symbol] :=
With[{
positions =
Flatten@Map[
Range[#1 + 1, #2 - 1] & @@@
SequencePosition[list,
(* this weird construction is necessary because
SequencePosition performs horribly with patterns
containing Repeated *)
Flatten@{sym, ConstantArray[_Integer, #], sym}] &][
Range[n]]},


A somewhat quicker method in the same rule-based paradigm would be to use ReplaceList to find all starting positions of all groups at once, and then make a batch replacement. Here is a possible implementation:

startPos[lst_, n_, sym_: x] :=
ReplaceList[
lst,
{l___, sym, Repeated[_Integer, {n}], sym, ___} :> Length[{l}] + 2
];


and the main function:

replace[lst_, n_, obj_: x, newobj_: y] :=
Module[{copy = lst},
copy[[Apply[Join]@Map[Range[#, # + n - 1] &]@startPos[lst, n, obj]]] = newobj;
copy
];


I did not benchmark, but the method based on ReplaceRepeated must have a quadratic complexity in the number of groups being replaced, while the one presented here should be linear time.

Using SequencePosition I create a function called sequenceReplace:

sequenceReplace[list_List, pattern:(pat:{p_}:> rhs_)]:=Replace[list,p :> rhs, 1]
sequenceReplace[list_List, pattern:(pat_List:> rhs_)]:=Block[{position, positionRules, newList = list},
position = SequencePosition[list, pat, Overlaps->False];
positionRules = <|"pos"-> First@#, "del"-> (#[[1]]+1;;#[[2]]), "new"-> FirstCase[{Take[list,#]}, pattern]|>&/@position;
Map[(newList[[#["del"]]] = Nothing; newList[[#["pos"]]] = #["new"])&, Reverse[positionRules]];
newList
]


The idea is to make easier to handle sequence replacements like:

list = {1, "a", 1, "b", 2, 2, 3}
sequenceReplace[list, {s_String, n_Integer} :> StringRiffle[{s, n}, ":"]]


{1, "a:1", "b:2", 2, 3}

For this question, It can be used as:

list = {1, x, 3, x, 4, x, x, 3, 4, 3, x, 2, 3, x, 8, 7};
n = 2;
sequenceReplace[list, {x,z:Repeated[_Integer,n],x}:> Sequence@@Flatten@{x,ConstantArray[y, Length@{z}],x}]


{1, x, y, x, 4, x, x, 3, 4, 3, x, y, y, x, 8, 7}

Strangely, as mentioned by @Pillsy, SequencePositon has a weird performance with Repeated, that makes @Oleksandr R. response with a better response time.