Collections & LINQ · Lesson 17

Set operations for reconciliation

Find shared, missing, and combined identifiers between two batches.

How it works

Set operations describe relationships between groups of unique values. Intersection finds values in both groups, difference finds values in one group but not another, and union combines both without duplicates. These operations are useful for reconciling expected and observed identifiers, comparing feature selections, or finding which subscriptions changed between two snapshots.

The direction of a difference matters. Expected minus observed identifies missing values, while observed minus expected identifies unexpected values. Name those results according to the question they answer. A set deliberately discards duplicate counts, so it cannot reveal that an identifier appeared three times in one source. If occurrence counts are part of the requirement, first build a frequency map or another representation that preserves them.

Walk through the example. The expected set contains A, B, and C, while the observed set contains B, C, and D. Intersect produces B and C. Except in the expected-to-observed direction produces A, and reversing the operands produces D. Union contains all four identifiers. Each result is ordered before joining so the report's text has a stable order.

Watch the boundary. Some HashSet methods mutate the receiving set, whereas the LINQ operations used here produce sequences without modifying the source sets. Be explicit about which form you choose, especially when a snapshot is reused later. Also supply compatible equality rules to all participating operations; mixing case-sensitive and case-insensitive interpretations can create a reconciliation report that contradicts itself.

Practice independently. Reconcile an enrolled-student set with an attendance set and produce present, absent, and unexpected reports. Define the identifier comparison rules before loading data. Include repeated input rows and show why they do not increase a set count. Then add a separate duplicate report so that the reconciliation preserves both membership information and evidence about repeated records.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

var expected = new HashSet<string>(new[] { "A", "B", "C" }, StringComparer.Ordinal);
var observed = new HashSet<string>(new[] { "B", "C", "D" }, StringComparer.Ordinal);
string Show(IEnumerable<string> values) => string.Join(",", values.OrderBy(x => x, StringComparer.Ordinal));
Console.WriteLine(Show(expected.Intersect(observed, StringComparer.Ordinal)));
Console.WriteLine(Show(expected.Except(observed, StringComparer.Ordinal)));
Console.WriteLine(Show(observed.Except(expected, StringComparer.Ordinal)));
Console.WriteLine(Show(expected.Union(observed, StringComparer.Ordinal)));

Expected output

B,C
A
D
A,B,C,D
Try this
Name both directions of a difference, and do not expect sets to preserve occurrence counts.