danturn 1 Light Poster

Hey guys,

I've got 2 collections (one datatable and one list of an object)

i need to compare them and get a collection of the matches and a collection of the items that dont match (from both collections)

i've got the matched collection sorted:

var yourNumbers = from DataRow yourNumber in yourNumberList.Rows
                               select new
                               {
                                   type = yourNumber["DDITYPEID"].ToString(),
                                   extension = yourNumber["EXTENSION"].ToString()
                               };

            var myNumbers = from myNumber in myNumberList
                              select new
                              {
                                  type = myNumber.type,
                                  extension = myNumber.number,
                                  key = myNumber.key
                              };

            var matchedNumbers = from vossNumber in vossNumbers
                                 join smartNumber in smartNumbers on vossNumber.extension equals smartNumber.extension
                                 select new
                                 {
                                     smartNumber.type,
                                     smartNumber.extension,
                                     vossNumber.key
                                 };

that works fine, but im struggling with the unmatched.

i've tried this:

var unmatchedNumbers =
                myNumbers.Except(myNumbers.Join(yourNumbers, myNumber => myNumber.extension,
                                                    yourNumber => yourNumber.extension,
                                                    (myNumber, yourNumber) => myNumber));

which returns items that are in the mynumber list only but not items that are only in the yournumber list.

any ideas?

dan

Dani AI

Generated

Your Except result makes sense because Enumerable.Except only returns items from the first sequence that are not in the second. It never returns items unique to the second sequence, so you need to compute both sides (or do a full outer join) to get the full set of non-matches. See Enumerable.Except.

If you are matching by extension only, project to that key and filter both directions. Using a HashSet keeps it fast and avoids tricky anonymous-type equality:

// Project to comparable shapes first
var tableNums = yourNumberList.AsEnumerable()
    .Select(r => new { Type = r.Field<string>("DDITYPEID"), Ext = r.Field<string>("EXTENSION") });

var listNums = myNumberList
    .Select(x => new { Type = x.type, Ext = x.number, x.key });

// Build lookup sets by key
var tableKeys = new HashSet<string>(tableNums.Select(n => n.Ext));
var listKeys  = new HashSet<string>(listNums.Select(n => n.Ext));

// Unmatched on each side
var onlyInList  = listNums.Where(n => !tableKeys.Contains(n.Ext));
var onlyInTable = tableNums.Where(n => !listKeys.Contains(n.Ext));

If you prefer a single query style, do a pair of outer joins and take the null side. This gives you unmatched from both collections:

var leftOnly =
    from l in listNums
    join t in tableNums on l.Ext equals t.Ext into g
    from t in g.DefaultIfEmpty()
    where t == null
    select l;

var rightOnly =
    from t in tableNums
    join l in listNums on t.Ext equals l.Ext into g
    from l in g.DefaultIfEmpty()
    where l == null
    select t;

That is the LINQ-to-Objects equivalent of a full outer join using GroupJoin + DefaultIfEmpty GroupJoin. Note: if type must also match, join on a composite key: new { Ext, Type }. If your DataTable may contain DBNulls, prefer Field<T> with AsEnumerable DataTableExtensions.AsEnumerable.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.