7
$\begingroup$

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

$\endgroup$
3
  • $\begingroup$ 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. $\endgroup$
    – Bill
    Commented Oct 9, 2014 at 19:56
  • $\begingroup$ 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. $\endgroup$
    – Literal
    Commented Oct 9, 2014 at 20:07
  • $\begingroup$ You could look at DeleteDuplicates or Split + First $\endgroup$
    – mfvonh
    Commented Oct 9, 2014 at 20:51

7 Answers 7

6
$\begingroup$

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}]
$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$
    – Literal
    Commented Oct 9, 2014 at 21:10
  • $\begingroup$ @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. $\endgroup$
    – ybeltukov
    Commented Oct 9, 2014 at 21:28
5
$\begingroup$

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}} *)
$\endgroup$
2
$\begingroup$
  • 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"]

enter image description here

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)

$\endgroup$
2
$\begingroup$

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}}*)
 
$\endgroup$
2
  • 1
    $\begingroup$ What is list2? $\endgroup$
    – Syed
    Commented Dec 16, 2023 at 2:14
  • 1
    $\begingroup$ 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. :-) $\endgroup$ Commented Dec 16, 2023 at 2:16
1
$\begingroup$

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};

list //. {head___, x_, x_, tail___} :> {head, x, tail}

{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}};

matrix //. {head___, x_, x_, tail___} :> {head, x, tail}

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

$\endgroup$
1
$\begingroup$

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}}

$\endgroup$
1
$\begingroup$
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}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.