48
$\begingroup$

I'm new to functional programming of Mathematica and trying to remove one list of assorted elements from another. However I only find functions working with the Index rather than the values itself:

 list1={b,a,e,f,c,d}  
 list2={f,e,c}

I can now remove list2 from list1:

 result={b,a,d}  

I already found out, that you can "abuse"

DeleteCases[list1, a] 

to remove 1 specific element from a list, but not a whole assorted list...

I would be very grateful for a simple solution to do it.
Thanks a lot for any answer!

$\endgroup$
1
  • 3
    $\begingroup$ Not functional, but just for fun: list1 /. Thread[list2 -> Nothing] $\endgroup$
    – user1066
    Apr 7, 2016 at 20:08

10 Answers 10

60
$\begingroup$

Use

DeleteCases[list1, Alternatives @@ list2]

In new versions (M8.0+), DeleteCases is optimized on patterns not involving blanks, so this will be fast also for large lists. For earlier versions, this will work:

Replace[list1, Dispatch[Thread[list2 -> Sequence[]]],{1}]

being 2-3 times slower, but still very fast.

$\endgroup$
9
  • $\begingroup$ thank you a lot, I do have V.8 and it works perfectly! Thank you for the fast answer! $\endgroup$ Feb 4, 2012 at 9:07
  • $\begingroup$ Thanks for including version-specific information; if you had not I would be left guessing. $\endgroup$
    – Mr.Wizard
    Feb 4, 2012 at 9:38
  • $\begingroup$ Thanks a lot, this works for any nested list! :) Great solution! $\endgroup$
    – Lady InRed
    Oct 5, 2012 at 9:58
  • $\begingroup$ @AnastasiiaAnishchenko No problem :-). Actually, it only works on level 1. You probably meant that elements can be anything, including being themselves lists. Actually, I have developed a more general set of routines for similar kinds of operations, see the UnsortedOperations package on this page $\endgroup$ Oct 5, 2012 at 14:24
  • $\begingroup$ @LeonidShifrin I am curious about the principle of DeleteCases. Why is it so fast than Select[list1, FreeQ[list2, #] &]? And I don't know the principle of Dispatch either. May be they have the same principle? $\endgroup$
    – matheorem
    Nov 21, 2013 at 13:37
30
$\begingroup$

You are perhaps searching for Complement. Complement[list1, list2] results in {a, b, d}. The result is sorted though. If you are looking for an unsorted complement, DeleteCases[list1, Alternatives @@ list2] should probably work. I think there are some discussions on unsorted complements out there at google.

$\endgroup$
4
  • 1
    $\begingroup$ Uh, Leonid beat me here. Should I leave the answer here anyway? $\endgroup$
    – Yves Klett
    Feb 4, 2012 at 9:05
  • 3
    $\begingroup$ Keep it, why not? I did not mention Complement (I actually implicitly assumed that the resulting list should not be sorted, which may or may not be the case). $\endgroup$ Feb 4, 2012 at 9:10
  • $\begingroup$ yes this is true. I found Complement on google, but I need the result to be unsorted. $\endgroup$ Feb 4, 2012 at 9:50
  • 3
    $\begingroup$ @PeriodicProgrammer Next time, please remember to include what you've tried and your constraints (unsorted), so that people don't waste time suggesting that. $\endgroup$
    – rm -rf
    Feb 4, 2012 at 13:25
21
$\begingroup$

Iff each list is internally free of duplicates you can use this very quick method:

DeleteDuplicates[#2 ~Join~ #] ~Drop~ Length[#2] &[list1, list2]
$\endgroup$
2
  • 3
    $\begingroup$ Clever trick. +1. $\endgroup$ Feb 4, 2012 at 9:30
  • $\begingroup$ This will keep list 1 in its original order—just what I was looking for! $\endgroup$
    – Szabolcs
    Oct 10, 2020 at 15:40
18
$\begingroup$

Since Yves beat me narrowly to my first solution, here's another one using Select:

Select[list1, FreeQ[list2, #] &]
Out[2]= {b, a, d}

This does not sort your result.


You can also use Complement, which is more intuitive. Example:

Complement[list1, list2]
Out[1]= {a, b, d}

Note that this sorts your result (i.e., it is not in the same order, {b, a, d}).

$\endgroup$
13
$\begingroup$

Unsorted Complement. I think it originates from MathGroup. It accepts the SameTest option.

Options[UnsortedComplement] = {SameTest -> Automatic};
UnsortedComplement[all_, del___, opts : OptionsPattern[]] := 
  Replace[all, 
   List @@ (Rule[#, Sequence[]] & /@ Union[del, opts]), {1}];

all = RandomInteger[{0, 9}, {20}]
UnsortedComplement[all, {6, 2, 8}, {2, 3, 4}]

(*
  ==> {8, 4, 2, 5, 8, 8, 6, 6, 2, 1, 3, 1, 1, 2, 8, 0, 5, 5, 8, 1}

  ==> {5, 1, 1, 1, 0, 5, 5, 1}
*)

It also works with any head, not just List-s.

$\endgroup$
7
$\begingroup$

Just nest it:

Fold[DeleteCases[#1, #2] &, list1, list2]
$\endgroup$
4
$\begingroup$

I hesitate to add to this old discussion after these excellent answers and other essential reading especially here, but this amalgamation of many suggestions may be of interest. cutEverything[xx_, removeList__] removes all entries of all elements of removeList_ from xx_ regardless of their depth or whether they are duplicates. It leaves compounds in place and does not change the original list order.

x = 
  {pudepied, pudepied.txt, {pudepied}, {{{pudepied}}, {zap}, {{peter}}}, {{pudepied}}, 
   blah, zap, "Wolfram Language", {peter}, {{{}}}, mary, {{{{mary}}}}};

remove = {pudepied, peter, mary, {}};
cutEverything[xx_, removeList_] := 
  Replace[xx, x_List :> DeleteCases[x, Alternatives @@ removeList], {0, Infinity}]
cutEverything[x, remove]
 {pudepied.txt, {{zap}}, blah, zap, Wolfram Language}
$\endgroup$
1
  • $\begingroup$ Thank you. Fixed! $\endgroup$
    – pudepied
    Sep 28, 2020 at 10:09
3
$\begingroup$
DeleteElements[{b, a, e, f, c, d}, \[Infinity] \[Rule] {f, e, c}]

    (*{b, a, d}*)

Unfortunately, the new function DeleteElements is not faster:

In[1]:= list1 = RandomReal[1, 2*^4]; list2 = 
         Catenate[{RandomChoice[list1, 6*^3], RandomReal[1, 4*^3]}];

In[2]:= result0=DeleteElements[list1,list2];//AbsoluteTiming

Out[2]= {3.78426, Null}

In[3]:= result1=DeleteCases[list1,Alternatives@@list2];//AbsoluteTiming

Out[3]= {0.01786, Null}

In[4]:= result2=Replace[list1,Dispatch[Thread[list2->Sequence[]]],{1}];//AbsoluteTiming

Out[4]= {0.0342811, Null}

In[5]:= result3=Replace[list1,x_List:>DeleteCases[x,Alternatives@@list2],{0,Infinity}];//AbsoluteTiming

Out[5]= {0.0222806, Null}

In[6]:= result4=Fold[DeleteCases[##]&,list1,list2];//AbsoluteTiming

Out[6]= {24.3309, Null}

In[7]:= Equal[result0,result1,result2,result3,result4]

Out[7]= True

Other ways are much slower, so I omit them here.

$\endgroup$
3
$\begingroup$

To explore the preceding answer a little bit further:

list1 = {b, a, e, f, c, d};
list2 = {f, e, c};

DeleteElements[list1, list2]

{b, a, d}

If list1 contains duplicated elements:

list1 = {b, a, e, f, c, c, d};
list2 = {f, e, c};

Delete all elements:

DeleteElements[list1, list2]

{b, a, d}

Delete up to 1 element:

DeleteElements[list1, 1 -> list2]

{b, a, c, d}

$\endgroup$
1
$\begingroup$

Using Cases:

list1 = {b, a, e, f, c, d};
list2 = {f, e, c};

Cases[list1, x_ /; FreeQ[x, Alternatives @@ list2] :> x]

{b, a, d}
$\endgroup$
2
  • 1
    $\begingroup$ Similar: Pick[list1, FreeQ[#, Alternatives @@ list2] & /@ list1] $\endgroup$
    – eldo
    Nov 18, 2023 at 7:58
  • $\begingroup$ It's a very good solution, @eldo! Thanks for pointing it out. :-) $\endgroup$ Nov 18, 2023 at 20:30

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.