# Can I have an un-Unionised Complement?

Posted 3 years ago
3999 Views
|
10 Replies
|
15 Total Likes
|
 Hi, I have cats, fish and dogs. In[173]:= animals = {cat, dog , fish, dog, cat} Out[173]= {cat, dog, fish, dog, cat} I want to take out the fish. In[174]:= Complement[animals, {fish}] Out[174]= {cat, dog} Unfortunately Mathamatica killed one of my cat and one of my dog. I want a result that looks like: Out[173]= {cat, dog, dog, cat} or if Mathematica really wants to sort it, then: Out[173]= {cat, cat, dog, dog} How can I do it and make it fast?Thanks ahead, JánosP.S. The documentation says only that the result is sorted. The list returned by Complement is sorted into standard order. Well, it is not. In[175]:= Sort[animals] Out[175]= {cat, cat, dog, dog, fish} Sort does not eliminate duplicates. Complement is Union-ized. Very bad for my purpose.
10 Replies
Sort By:
Posted 3 years ago
 In[1]:= DeleteCases[{cat, dog, fish, dog, cat}, fish] Out[1]= {cat, dog, dog, cat} In[2]:= DeleteCases[{cat, dog, fish, dog, cat}, Alternatives @@ {cat, fish}] Out[2]= {dog, dog} 
Posted 3 years ago
 Thanks, but no good. In[3]:= DeleteCases[{cat, dog, fish, dog, cat}, cat] Out[3]= {dog, fish, dog} As you can see it deleted both cats. Well, in the meantime I solved my problem with Drop. Unfortunately it is not as fast as Complement. animals = {cat, dog, fish, dog, cat}; In[7]:= Drop[animals, First[Position[animals, cat]]] Out[7]= {dog, fish, dog, cat} I am working with time series where the same values just cannot be eliminated, because that falsifies the results.
Posted 3 years ago
 If your list contains sets of identical items, and you want just one of them dropped, which one is it that you want dropped? So this is much like you did above. If it is the first occurrence, we can just find its position in the list and drop it: In[1]:= list = {dog, dog, cat, fish , cat, dog} Out[1]= {dog, dog, cat, fish, cat, dog} In[2]:= dropFrom[list_, thing_] := Drop[list, Position[list, thing, 1, 1] // Flatten] In[3]:= dropFrom[list, cat] Out[3]= {dog, dog, fish, cat, dog} In[4]:= dropFrom[list, bear] Out[4]= {dog, dog, cat, fish, cat, dog} 
Posted 3 years ago
 As you can see it deleted both cats. Well, in the meantime I solved my problem with Drop. That's fine for a single element, of course DeleteCases can also handle it:  In[2]:= DeleteCases[{cat, dog, fish, dog, cat}, cat, {1}, 1] Out[2]= {dog, fish, dog, cat} 
Posted 3 years ago
 I am always overlooking the 3rd argument! :-)
Posted 3 years ago
 Thanks guys, The major reason I wrote in the first place was the misstatement in the documentation that Complement does a sort. If it would have done a Sort, everything would be just fine, because Sort does not eliminate duplicates. Yes, I always want to drop the first one because of the time dependence. Drop, Delete and DeleteCases are taking more time than Complement. In the case of big lists that is significant.
Posted 3 years ago
 What the documentation says is accurate, as the returned elements are indeed in canonical order.  In[1]:= Complement[{c, b, a, c}, {c}] Out[1]= {a, b} In[2]:= % === Sort[%] Out[2]= True The functions Union, Complement and Intersection are designed to work as the usual set-theoretic union, complement and intersection if the list arguments are considered as sets (which means repeated elements are ignored). This is explicitly documented for Union and Intersection. For example, In[3]:= Intersection[{b, a, a, a}, {b, a, a}] Out[3]= {a, b} and again the result is sorted.
Posted 3 years ago
 Just as an idea, something that also considers repetitions in the list of searched items: deleteCasesOnce[list_List, cases_List] := Module[{countq}, countq[_] := 0; Scan[(countq[#] = countq[#] + 1;) &, cases]; Reap[If[countq[#] === 0, Sow[#], countq[#] = countq[#] - 1] & /@ list][[2, 1]] ]; And this returns what you expect: In[]:= deleteCasesOnce[{cat, dog, fish, dog, cat, dog, cat, fish}, {cat, fish, cat}] Out[]= {dog, dog, dog, cat, fish} 
 For multiple elements deletion, here are some fast implementation:Removing elements from a list which appear in another list.If you like terse coding (not so fast really), there is a closely related topic: In[]:= Fold[ DeleteCases[ ##, 1, 1]&, {cat, dog, fish, dog, cat, dog, cat, fish}, {cat, fish, cat}] Out[]:= {dog, dog, dog, cat, fish}