Loved SLaks version. Just for completeness, you can use HashSet method IsSubsetOf when performing set operations (also check IsSupersetOf method). There are pros and cons for this approach. Next code shows an example:
var list1 = new HashSet<string>{ "Dog", "Cat", "Bird" };
var list2 = new HashSet<string>{ "Dog", "Cat" };
if (list2.IsSubsetOf(list1))
{
Console.Write("All items in list2 are in list1");
}
Except method is streaming in nature. In query list2.Except(list1) list1 is buffered completely into memory, and you iterate one item at a time through list2. IsSubsetOf works eagerly in the opposite manner. This starts to make a difference when you have huge sets of data.
To analyse the worst case performance, here is some code from Except implementation at Monos Enumerable (dotPeek gives very similar results, just less readable)
var items = new HashSet<TSource> (second, comparer); //list1.Count
foreach (var element in first) //list2.Count
if (items.Add (element)) //constant time
yield return element;
as result O(list1.Count + list2.Count), loops aren't nested.
IsSubset has next method call, if second IEnumerable is HashSet (decompiled via dotPeek):
private bool IsSubsetOfHashSetWithSameEC(HashSet<T> other)
{
foreach (T obj in this) //list2.Count
if (!other.Contains(obj)) //constant time
return false;
return true;
}
Resulting in O(list2.Count) if list1 is a HashSet.