2
$\begingroup$

I want to delete one of each (and not all) selected element in a list containing duplicates.

For example i have the list: $\{1,1,1,2,2,3\}$ and i want to delete $\{1,3\}$ so the leftover should be $\{1,1,2,2\}$ (and not $\{2,2\}$).

I tried working with $DeleteCases$ and $Alternatives$, but could only delete all elements which match the pattern:

r={1,1,1,2,2,3}; 
del={1,3};
DeleteCases[r, Alternatives @@ del]

Little side question: Is there a better way for adding elements than

add={4,5};  
Flatten[Append[r, add]]

?

Thanks a lot, kon

$\endgroup$
1
  • $\begingroup$ For your little question, Flatten[{r,add}], or AppendTo[r,add] or Join[r,add] I think should all work... $\endgroup$
    – tkott
    Mar 24, 2015 at 14:05

3 Answers 3

5
$\begingroup$

You can use the fourth argument of DeleteCases to specify how many instances of a case to delete:

dcF = Fold[DeleteCases[##, 1, 1] &, ##] &;

r = {1, 1, 1, 2, 2, 3};

dcF[r, {1, 3}]
(* {1, 1, 2, 2} *)

dcF[r, {1, 1}]
(* {1, 2, 2, 3} *)

dcF[{a, a, a, 2, 2, c}, {2, 2, 2, c, c, c}]
(* {a, a, a} *)

Update:

is it possible to return {0} when trying to delete more instances of a case then r contains

delF[r_, del_] := If[Min[Count[r, #1] - #2 & @@@ Tally[del]] < 0, {0},
                     Fold[DeleteCases[##, 1, 1] &, r, del]]
delF[{1, 1, 1, 2, 2, 3}, {1, 1, 2, 2}]
(* {1, 3} *)
delF[{1, 1, 1, 2, 2, 3}, {1, 1, 2, 2, 2}]
(* {0} *)
$\endgroup$
5
  • $\begingroup$ is it possible to return {0} when trying to delete more instances of a case then r contains? $\endgroup$
    – kon
    Mar 24, 2015 at 16:42
  • $\begingroup$ @kon, please see the update. $\endgroup$
    – kglr
    Mar 24, 2015 at 17:25
  • $\begingroup$ @kguler Ha! I forgot to check the docs on DeleteCases itself. $\endgroup$
    – tkott
    Mar 24, 2015 at 17:58
  • $\begingroup$ @tkott, third/fourth optional arguments are easy to forget:) When i find myself wishing a certain function handled a new/seemingly-new case i first check the docs for alternative signatures. $\endgroup$
    – kglr
    Mar 24, 2015 at 18:23
  • $\begingroup$ @kguler it works fine, thank you $\endgroup$
    – kon
    Mar 25, 2015 at 9:12
2
$\begingroup$

The way I would approach this is:

delParts = First /@ (Position[r, #] & /@ del)

Then

Delete[r, delParts]

I.e., find the position of all the pieces you want, separated into groups, take the first part of each group, and delete there.

$\endgroup$
2
  • $\begingroup$ I just realised it does not work when trying to delete two of the same element: eg.: del={1,1} $\endgroup$
    – kon
    Mar 24, 2015 at 16:05
  • $\begingroup$ Could it also return {0} when you try to delete more elements than r contains? Like del={3,3}? $\endgroup$
    – kon
    Mar 24, 2015 at 16:31
1
$\begingroup$

Using pattern matching:

r = {1, 1, 1, 2, 2, 3};
del = {1, 3};

Fold[Replace, r, {{s___, #, e___} -> {s, e}} & /@ del]

{1, 1, 2, 2}

$\endgroup$

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