Click here to Skip to main content
15,884,537 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
C#

Hello guys,
I am trying to compare 2 list of custom objects.
Here is my setup:

C#
Class <Entity>
{
     string ID;
     int Amount;

     public Entity(string _ID, int _Amount)
     {
        ID = _ID; Amount = _Amount;
     }
}
In the further code I have this:

C#
List<Entity> E1 = mew List<Entity>();
List<Entity> E2 = mew List<Entity>();

C#
E1.Add(new Entity("A1", 1));
E1.Add(new Entity("A1", 1));
E1.Add(new Entity("B1", 3));
E1.Add(new Entity("C1", 5));

E2.Add(new Entity("A1", 1));
E2.Add(new Entity("D1", 7));
E2.Add(new Entity("F1", 8));
E2.Add(new Entity("F1", 8));


So - 1st question - how to remove duplicates from these 2 lists? E1 has doubled ["A1", 1] combination and E2 has ["F1", 8] combination.

I have tried using this:
C#
E1 = E1.distinct().ToList()
E2 = E2.distinct().ToList()
But that did not help... any help would be appreciated.

Question #2.
I want to return 3rd list which would contain the items that are in list E1, but not in list #2.
I have tried this LINQ query:
C#
var distinction = (from item in E2
                  where !E1.Contains(item)
                  select item).ToList();
Though that does not quiet work - it returns items that are present in both... so I'm quiet lost in here.... I was thinking about implementing IComparable interface on Entity class, but not really sure... would appreciate if you could at least show me the right path or give some example to turn my brains on :)

Thanks in advance!
Posted
Updated 17-Jan-14 3:41am
v3
Comments
Karthik_Mahalingam 17-Jan-14 9:59am    
Solution 1 Deleted Pls ignore...
Check Solution 2

Try this..



C#
using System.Collections.Generic;
using System;
using System.Linq;


class Program
{

    static void Main(string[] args)
    {
        List<entity> E1 = new List<entity>();
        List<entity> E2 = new List<entity>();
        E1.Add(new Entity("A1", 1));
        E1.Add(new Entity("A1", 1));
        E1.Add(new Entity("B1", 3));
        E1.Add(new Entity("C1", 5));

        E2.Add(new Entity("A1", 1));
        E2.Add(new Entity("D1", 7));
        E2.Add(new Entity("F1", 8));
        E2.Add(new Entity("F1", 8));
        // remove duplicates

        E1 = E1.Distinct(new EntityComparer()).ToList();
        E2 = E2.Distinct(new EntityComparer()).ToList();

        // question 2 

      var newresult = E1.Where(k => !E2.Contains(k, new EntityComparer())).ToList();   


        Console.ReadLine();
    }
}

class EntityComparer : IEqualityComparer<entity>
{ 
    public bool Equals(Entity x, Entity y)
    {
        return x.ID == y.ID; 
    }


    public int GetHashCode(Entity obj)
    {
        return 0;
    }
}

class Entity
{
    public string ID { get; set; }
    public int Amount { get; set; }

    public Entity(string _ID, int _Amount)
    {
        ID = _ID; Amount = _Amount;
    }
}
 
Share this answer
 
v2
Comments
MK-Gii 17-Jan-14 10:14am    
I had to update one line to make it work correctly. but generaly - very good answer. Thanks!
P.S.: in this example the comparer is only comparing the ID - not the whole item. So in case we have ["A1", 1] and ["A1", 2] it will call these equal. I have change this:
return x.ID == y.ID;
to this:
return x.ID == y.ID && x.Amount == y.Amount;
And that worked like a charm.
Cheers!
Karthik_Mahalingam 17-Jan-14 11:29am    
thanks dude :)
BillWoodruff 17-Jan-14 11:27am    
+5 you got the OP home !
Karthik_Mahalingam 17-Jan-14 11:29am    
THanks Bill :)
Maciej Los 17-Jan-14 11:44am    
+5
If you just don't feel like implementing an IEqualityComparer, as Karthik neatly shows you how to do, there is an alternative: you do need to override Equals in your Entity Class:
C#
public class Entity
{
     public string ID;
     public int Amount;

     public Entity(string _ID, int _Amount)
     {
        ID = _ID; Amount = _Amount;
     }

     public override bool Equals(object obj)
     {
         Entity e2 = obj as Entity;

         // edge cases ? not really necessary ?
         //if (ReferenceEquals(this, e2)) return true;

         //if (e2 == null && this != null) return false;

         //if (this == null && e2 != null) return false;

         return this.ID == e2.ID && this.Amount == e2.Amount;
     }
}
Then you can do this:
C#
List<Entity> E1 = new List<Entity>();
List<Entity> E2 = new List<Entity>();

private void TestListFilteringAndMerging(object sender, EventArgs e)
{
    E1.Add(new Entity("A1", 1));
    E1.Add(new Entity("A1", 1));
    E1.Add(new Entity("B1", 3));
    E1.Add(new Entity("C1", 5));

    E2.Add(new Entity("A1", 1));
    E2.Add(new Entity("D1", 7));
    E2.Add(new Entity("F1", 8));
    E2.Add(new Entity("F1", 8));

    // test Equals override
    // Console.WriteLine(E1[0].Equals(E2[0])).ToString());

    // eliminate duplicates in each List
    E1 = E1.GroupBy(e1 => e1.ID).Select(e2 => e2.First()).ToList();
    E2 = E2.GroupBy(e1 => e1.ID).Select(e2 => e2.First()).ToList();

    // merge two Lists and eliminate duplicates in merged List
    List<Entity> JoinE1E2 = E1.Concat(E2).GroupBy(e1 => e1.ID).Select(e2 => e2.First()).ToList();

    // examine merged List
    foreach(Entity theEntity in JoinE1E2)
    {
        Console.WriteLine(theEntity.ID + " : " + theEntity.Amount.ToString());
    }
}
However, I'd recommend you go ahead and use the solution Karthik showed you, because: I think it is more readable, probably more maintainable over time ... just all-around more "standard."

I shudder to think of trying to explain the clever use of Linq here ... even to myself :)

And, note that VS 2013 will give you a warning (but not stop compilation) that you have not over-ridden 'GetHashCode.
 
Share this answer
 
v3
Comments
Maciej Los 17-Jan-14 11:44am    
+5
Karthik_Mahalingam 17-Jan-14 12:25pm    
5!
See my past answer: how to compare dates in one array[^].
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900