Set Difference Minus Operation with LINQ in C#


Sometimes you want to use a Difference (or Minus) set operation which goes like this: Give me all elements from set A that do not exist in set B.  Or simply put A – B.  The LINQ Except method does this if both sets A and B are of the same type, but frequently the sets are of different types and must have their identifiers matched.  Here is a quick little example of how to do this with LINQ.

Wolfram MathWorld shows the operation’s definition as: 

static void Main(string[] args)
{
  List<string> names = new List<string>
  { "Noah", "Sarah", "Josiah", "Craig", "Carolin" };
 
  Dictionary<string, string> visiting = new Dictionary<string, string>()
  { { "Noah", "Turkey" }, { "Craig", "Germany" }, { "Sue", "Bangalore" } };
 
  var minus =
    from n in names
    let places = from p in visiting select p.Key
    where !places.Contains(n)
    select n;
 
  foreach (var v in minus)
    Console.WriteLine(v);
 
  Console.ReadKey();
}

Output:

Sarah 
Josiah 
Carolin

The dot notation way of doing this would be "names.Where(a => !visiting.Select(b => b.Key).Contains(a))".  I realize this all seems to be relatively trivial for one familiar with LINQ, but at the time of writing this there isn’t a decent topic popping up on Bing or Google when searching for LINQ Minus C# with two types of sets, now hopefully there will be. If you know of a more efficient way, please by all means post a comment, thanks.

References

Comments (4)

  1. var minus = names.Except(visiting.Select(p => p.Key));

  2. noahc says:

    Thanks for the simifilcation Justin.  I believe I over simplified my example.  My goal was to show the difference operation with two completely different types of sets, but since set A is a relatively simple type, your example worked well.  If set A was of type "Customer" and set B was of type "Travel Plans" it would be more challenging.

  3. Nidhi says:

    This one is just too good and helpful…..thanks!!

  4. Matt says:

    I agree with Justin here. The example can easily simplified, and if it were more complicated as you suggested, then your solution wouldn’t work either?

    Ultimately you’ll be comparing two sets, if they’re off the same type, and the object implements Equals, you can use Except(). If you can use Contains() on a property of your class as per your example, you can use Except() after using  Select().

    i.e. customers.Select(c=> <equality data>).Except(travelPlan.Select(tp => <equality data>)