# Sublist pattern matching

Is there any way to simplify the following pattern:

{p___, {a___, x_, x_, b___}, q___} :> {p, {a, x, b}, q}


Ie. where I remove duplicated elements within sublists?

Edit: Just to be clear, I have the feeling p and q could be removed here, but well I'm not certain :)

Thanks

• Think. If you remove the p and q and you happened to have two adjacent sublists that were identical, what would happen then? Something like {{3,4},{5,7,7,2},{5,7,7,2},{2,8}} Compare that example with and without the p and q and see what happens. Then think about it until you can explain what happened. Then try all this using /. and //. It all depends on what you want to accomplish.
– Bill
Commented Oct 9, 2014 at 19:56
• Well exactly, that's why I kept them. But since p and q remain at the same place I thought I could have removed them. Besides, it assumes here that I'm working at the second level of my main list, but what if I didn't know which level they were at? Anyway, it might just be the most simple expression but I had the intuition it wasn't so. And btw it's a repeated pattern //. here. Commented Oct 9, 2014 at 20:07
• You could look at DeleteDuplicates or Split + First Commented Oct 9, 2014 at 20:51

Several demonstrative examples:

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

list /. {p___, {a___, x_, x_, b___}, q___} :> {p, {a, x, b}, q}
(* {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 3, 5}} *)

list /. {a___, x_, x_, b___} :> {a, x, b}
(* {{1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}} *)

Replace[list, {a___, x_, x_, b___} :> {a, x, b}, {1}]
(* {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}} *)


I think the last one is what you are looking for.

If you want to delete many sequential duplicates with patterns you can use

Replace[list, {a___, Repeated[x_, {2, ∞}], b___} :> {a, x, b}, {1}]

• Sweet. Yeah the last answer with the levelspec argument is what I was looking for. It's too bad it can't be expressed using the /. syntax though. One last question, I'm not certain why the first pattern (the which I submitted doesn't catch the {1, 3, 3, 5} list. Commented Oct 9, 2014 at 21:10
• @Neuschwanstein It is because the whole list matches the pattern and /. applies the substitution, but this substitution eliminate only one duplicate. You should use //. (ReplaceRepeated) to apply replacement repeatedly. Note, that ReplaceRepeated is very slow for big lists due to matching the whole list a lot of times. Commented Oct 9, 2014 at 21:28

Map ReplaceAll at Level 1:

# /. {a___, x_, x_, b___} :> {a, x, b} & /@ list
(* {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}} *)


Map DeleteDuplicates at Level 1:

DeleteDuplicates /@ list
(* {{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}} *)


Alternative methods to ReplaceRepeated to get {{1, 2, 3}, {1, 3, 5}}:

FixedPoint[# /. {a___, x_, x_, b___} :> {a, x, b} &, list]
(* {{1, 2, 3}, {1, 3, 5}} *)

Map[DeleteDuplicates, list, {0, 1}]
(* {{1, 2, 3}, {1, 3, 5}} *)


And to get {{1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}}:

Map[# /. {a___, x_, x_, b___} :> {a, x, b} &, list, {0}]
(* {{1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}} *)


or

Map[DeleteDuplicates, list, {0}]
(* {{1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}} *)

• Duplicated elements in a list can be removed by DeleteDuplicates without changing list order. Duplicated elements can be non-consecutive.

• Using Union will sort the list which may or may not be desired.

• Sequence* functions were introduced in 2018 and are a natural fit for the task or removing consecutively appearing elements.

Entity["WolframLanguageSymbol"
, "SequenceReplace"]["DateIntroduced"]


Clear["Global*"]
list = {
{1, 2, 3}
, {1, 2, 3}
, {1, 2, 2, 3}
, {1, 3, 3, 5}
, {1, 3, 4, 5, 5, 5, {5}, {5}, 6, 7, 8}
, {1, 1, 2, 2, 3, 4, 6, 6, 4, 5, 5, 9}
};


where a few additional test cases have been introduced to demonstrate removal of repeated/sublisted items.

The following deletes any number of similar and consecutive elements in list but not inside the sublists.

SequenceReplace[list, {x_ ..} ->  x]


{{1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}, {1, 3, 4, 5, 5, 5, {5}, {5},
6, 7, 8}, {1, 1, 2, 2, 3, 4, 6, 6, 4, 5, 5, 9}}

Defining this as a function and applying it to each sublist:

f = SequenceReplace[#, {x_ ..} ->  x] &
f /@ list


{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}, {1, 3, 4, 5, {5}, 6, 7,
8}, {1, 2, 3, 4, 6, 4, 5, 9}}

More selectivity with repetition count can be achieved using options for Repeated.

Try: f@(f /@ list)

An alternative is to use Cases, Tally and Union as follows:

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

delRepeated[l_List, opts___] := Which[opts === Null,
Cases[l, x_ :> Tally[x][[All, 1]]],
opts === "Sorted", Union /@ l];

delRepeated[list]

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

delRepeated[list, "Sorted"]

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


• What is list2?
– Syed
Commented Dec 16, 2023 at 2:14
• Thanks for pointing out the error, @Syed, it's that I tried it with another list that I denoted like this and when copying I forgot to change it. :-) Commented Dec 16, 2023 at 2:16

If I don't missunderstand your question this could be a good candidat for ReplaceRepeated

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



{1, 2, 3, 1, 7}

To scrutinise @ ybeltukov's excellent answer and your nice but ambiguous question

matrix = {{1, 2, 3}, {1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}};



{{1, 2, 3}, {1, 3, 5}}

Another option to consider is to only (repeatedly) replace if the repeated item is an atom:

rule = {a___, x_?AtomQ, x_, b___} :> {a, x, b}


In action:

{{1, 2, 3}, {1, 2, 3}, {1, 2, 2, 3}, {1, 3, 3, 5}} //. rule


{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}}

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


Using SequenceSplit (new in 11.3)

ReplaceAll[{a_} :> a] @ Map[SequenceSplit[#, {a_, a_} :> a] &, list]


{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}}

Using Split

Map[First, Split[#, #1 == #2 &] & /@ list, {2}]
`

{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 3, 5}}