0

I have two lists in C#. I need a LINQ query to compare and list only unmatched rows.

List<First> firstList;
List<Second> secondList;
both have the unique property called ID;

firstList:

ID  Desc1   Desc2           
1   aaa     mmm             
2   bbb     fff             
3   ccc     ttt   
4   ddd     yyy
5   eee     ggg

secondList:

ID  Desc1   Desc2   Status          
1   aaa     mm      P       
2   bbb     fff     S       
3   ccc     ttt     P   
4   ddd     yy      S
5   eee     ggg     P

Result:

ID  Desc1   Desc2   Status
2   aaa     mm      P
4   ddd     yy      S

I want to compare the Desc1 and Desc2 in firstList with the secondList and need the Status of Items which are not matching.

karel
  • 5,489
  • 46
  • 45
  • 50
rajeshnrh
  • 55
  • 1
  • 3
  • 9
  • 2
    What did you try to achieve this? Where are you stuck? – MakePeaceGreatAgain Mar 22 '19 at 21:47
  • I need to find status of unmatched rows by comparing multiple fields. I am learning C#, don't know how to acheive this. – rajeshnrh Mar 22 '19 at 22:06
  • 1
    There´s no big learning-factor if we would give you the ready to use solution, would it? And this is why this site doesn´t work like this, you have to provide your attemps and provide information on where **specifically** you´re stuck. You should aso have a look at https://stackoverflow.com/help/how-to-ask. – MakePeaceGreatAgain Mar 22 '19 at 22:17
  • Unfortunately my visual studio got crashed, Ill take care in future. – rajeshnrh Mar 23 '19 at 13:42
  • What you're asking for is the difference between two lists. This question has already been answered. See https://stackoverflow.com/questions/5636438/difference-between-two-lists. – koolahman Mar 22 '19 at 22:34

3 Answers3

3

some methods to find the result (lambda, linq):

var query0 = secondList.Where(item => firstList.All(f => !item.Desc1.Equals(f.Desc1)  || !item.Desc2.Equals(f.Desc2)));

or

var query1 =
    from item in secondList
    where firstList.All(f => !item.Desc1.Equals(f.Desc1) || !item.Desc2.Equals(f.Desc2))
    select item;

if you want the result in a list instead enumeration, you just add Tolist() at the end:

var list0 = secondlist.Where(item => firstlist.All(f => !item.Desc1.Equals(f.Desc1) || !item.Desc2.Equals(f.Desc2))).ToList();

To answer at your question in comment:

if you want to iterate or select a particularID you could do that:

        foreach(var item in query0)
        {
           Console.WriteLine($"ID:{item.ID}, Desc1:{item.Desc1}, Desc2:{item.Desc2}, Status:{item.Status}");  
        }

        //if you want to query a particular id:
        var queryid = query0.Where(item => item.ID == particularID);
Frenchy
  • 16,386
  • 3
  • 16
  • 39
0

Please see below. You need to do union between the two lists and then remove the intersection. You will need to implement the IEqualityComparer interface.

void Main()
{
    List<UserProfile> u1 = new List<UserQuery.UserProfile>(){
        new UserProfile(){ID = 1, FirstName  = "Super" , LastName = "Man"},
        new UserProfile(){ID=2, FirstName = "Spider", LastName="Man"},
        new UserProfile(){ID=3, FirstName = "Bat", LastName="Man"}
    };

    List<UserProfile> u2 = new List<UserProfile>(){
        new UserProfile(){ID = 1, FirstName="Super", LastName="Man"},
        new UserProfile(){ID = 2, FirstName="Thor", LastName="Ragnarok"},
        new UserProfile(){ID = 3, FirstName="Hulk", LastName="Baner"}
    };

//  u1.Intersect(u2, new UserProfileComparer())
//      .ToList()
//      .ForEach(x => Console.WriteLine(x.Name));

//  u1.Except(u2, new UserProfileComparer())
//      .ToList()
//      .ForEach(x => Console.WriteLine(x.Name));

    // (u1 + u2) - (u1*u2)
    u1.Union(u2, new UserProfileComparer())
        .Except(u1.Intersect(u2, new UserProfileComparer()))
        .Distinct()
        .ToList()
        .ForEach(x => Console.WriteLine(x.Name));
}

class UserProfile
{
    public int ID {get;set;}
    public string Name => LastName + "," + FirstName;
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

class UserProfileComparer : IEqualityComparer<UserProfile>
{
    public bool Equals(UserProfile item1, UserProfile item2)
    {
        if (object.ReferenceEquals(item1, item2))
            return true;
        if (item1 == null || item2 == null)
            return false;
        return item1.FirstName.Equals(item2.FirstName) &&
               item1.LastName.Equals(item2.LastName);
    }

    public int GetHashCode(UserProfile item)
    {
        return new { item.FirstName, item.LastName }.GetHashCode();
    }
}
jay.w
  • 83
  • 1
  • 6
0

I would suggest instead of using != like mentioned in other answers use join. If your list is huge != will consume lots of processing time.

Following code may look ugly but does serves the purpose and is faster.

var unmatchedRec = (from p in lstFiles1
    join f in lstFiles2
    on new
    {
        p.FileName,
        p.PageNumber
    } equals new
    {
        f.FileName,
        f.PageNumber
    } into fg
    from fgi in fg.DefaultIfEmpty()
    select new { p, fgi })
        .Where(t => t.fgi == null)
        .Select(t => t.p)
        .ToList();