# Pattern matching for repeated elements

Is there a pattern that can match repeated elements that appear more than twice in a row?

For the sake of example let's say I want to use pattern matching to delete subsequent duplicate:

l = {1,2,2,3,4};

l/.{b___,x_,x_,r___}->{b,r}

(*{1,3,4}*)


But

l = {1,2,2,2,3,4};

l/.{b___,x_,x_,r___}->{b,r}

(*{1,2,3,4}*)


I can try to use Repeated, but it doesn't seem to work:

l = {1, 2, 2, 2, 3, 4};

l /. {b___, x_, (x_) .., r___} -> {b, r}

(*{1,2,3,4}*)


Am I using it wrong?

Use the Longest pattern command to find the longest repeated sequence that matches the pattern.

l = {1, 2, 2, 2, 3, 4};

l /. {b___, x_, Longest[(x_) ..], r___} :> {b, r}

(*{1, 3, 4}*)

• That's helpful. However, when I try it on l={1,1,1,2} the result is {1,1,2}, and not {2} as I would expect. Commented Feb 4, 2021 at 14:59
• l={1,1,1,2} returns {2} when I test it. Are you sure that both the b and r have three blanks? Commented Feb 4, 2021 at 15:02
• My bad, I had missed the "repeated" on the Longest pattern. It does work! Commented Feb 4, 2021 at 15:18

Another possibility is to use SequenceReplace:

SequenceReplace[{1, 2, 2, 2, 3, 4}, {x_, x_ ..} -> Sequence[]]


{1, 3, 4}

Try the following:

l = {1, 2, 2, 2, 3, 4};
l /. {b___, x_, (x_) .., r___} -> {{b}, {r}}
(* {{1}, {2, 3, 4}} *)


and you see that that r is ill-defined. Therefore we must restrict r:

l //. {b___, Repeated[x_, {2, 10}], Shortest@r___} :> {b, r}
(*{1, 3, 4}*)

• Very nice debugging trick. I have already given the tick mark, but this would deserve one as well. Commented Feb 4, 2021 at 15:27

You might also consider using the two-argument form of Repeated for finer control:

{1, 2, 2, 3, 4}  /. {a___, Repeated[x_, {2, ∞}], b___} :> {a, b}

{1, 3, 4}

SequenceReplace[{1, 2, 2, 2, 3, 4}, {Repeated[x_, {2, ∞}]} -> Sequence[]]

{1, 3, 4}


Not pattern matching, but one other way:

Cases[Split@l2, {x_}:>x]


{1, 3, 4}

list = {1, 2, 2, 2, 3, 4};


Using PositionIndex

Keys @ Select[Length[#] == 1 &] @ PositionIndex[list]


{1, 3, 4}

list = {1, 2, 2, 2, 3, 4};


Using Cases and Tally

Cases[{a_, 1} :> a] @ Tally @ list


{1, 3, 4}

Using Select and Counts

Keys @ Select[SameAs @ 1] @ Counts @ list


{1, 3, 4}

Using Select and Count:

l = {1, 2, 2, 2, 3, 4};

Select[l, Count[l, #] == 1 &]

(*{1, 3, 4}*)


Also, using ReplaceAll:

f = # /. x_Integer :> If[Count[#, x] == 1, x, Nothing] &;

f@l

(*{1, 3, 4}*)


Also, using the third argument of GroupBy and Lookup:

Lookup[GroupBy[Normal@Counts[l], #[[2]] == 1 &, #[[All, 1]] &], True]

(*{1, 3, 4}*)