IMPORTANT CHANGE
As noted in the comments, .Except() uses the set internally, so any duplicate elements of list1 will be missing in the final result.
Makes the difference set of two sequences
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except(v=vs.110).aspx
However, there is a solution that is both O (N) and keeps duplicates in the original list: change the RemoveAll(i => list2.Contains(i)) approach RemoveAll(i => list2.Contains(i)) to use the HashSet<int> to store the exception set.
List<int> list1 = Enumerable.Range(1, 10000000).ToList(); HashSet<int> exclusionSet = Enumerable.Range(500000, 10).ToHashSet(); list1.Remove(i => exclusionSet.Contains(i));
The ToHashSet() extension method is available in MoreLinq .
ORIGINAL RESPONSE
You can use linq
list1 = list1.Except(list2).ToList();
UPDATE
Out of curiosity, I did a simple test of my decision against @ HighCore's.
For list2 , which has only one item, its code runs faster. As list2 gets bigger and bigger, its code becomes very slow. It looks like its O (N-square) (or, more specifically, O (list1.length * list2.length), since each item in list1 compared with every item in list2 ). I donβt have enough data to validate Big-O of my solution, but it is much faster when list2 has more than a few items.
Code used for verification:
List<int> list1 = Enumerable.Range(1, 10000000).ToList(); List<int> list2 = Enumerable.Range(500000, 10).ToList();
UPDATE 2
This solution assigns the new list to list1 . As @ Tolya points out, other links (if any) to the original list1 will not be updated. This solution is significantly superior to RemoveAll for all but the smallest list2 sizes. If no other links should see the update, this is preferable for this reason.