2

I'm trying to figure out how best to compare and merge two List<T> with a new List<T> being generated that compares multiple properties within each object.

class Account
{
    public Account() { }
    public string ID { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

List<Account> Mine = new List<Account>();
List<Account> Yours = new List<Account>();
List<Account> Ours = new List<Account>();

Account m1 = new Account(){ ID = null, Name = "C_First", Value = "joe" };
Account m2 = new Account(){ ID = null, Name = "C_Last", Value = "bloggs" };
Account m3 = new Account(){ ID = null, Name = "C_Car", Value = "ford" };

Mine.Add(m1);
Mine.Add(m2);
Mine.Add(m3);

Account y1 = new Account(){ ID = "1", Name = "C_First", Value = "john" };
Account y2 = new Account(){ ID = "2", Name = "C_Last", Value = "public" };

Yours.Add(y1);
Yours.Add(y2);

The resulting List<Account> Ours would have the following List<Account> objects:

{ ID = "1", Name = "C_First", Value = "joe" };
{ ID = "2", Name = "C_Last", Value = "bloggs" };
{ ID = null, Name = "C_Car", Value = "ford" };

I need to figure out how best to compare the ID and Value properties between both List<Account> objects where the List<Account> Yours ID takes precedence over the List<Account> Mine and the List<Account> Mine Value takes precedence over List<Account> Yours along with any object that's not in List<Account> Yours being added as well.

I've tried the following:

Ours = Mine.Except(Yours).ToList();

which results in List<Ours> being empty.

I've read this post Difference between two lists in which Jon Skeet mentions using a custom IEqualityComparer<T> to do what I need but I'm stuck on how to create an IEqualityComparer<T> that compares more than 1 property value.

Community
  • 1
  • 1
  • How do you define that two items represent the same but with different data? is just by name and value? – Ivo Oct 31 '13 at 05:40
  • By the Name property, so if the objects name properties are the same but the Value is different from one object to the other the List Mine would take precedence but the ID of List Yours would override the null value for ID in the List Mine. Hope that makes sense. – devin M. arnold Oct 31 '13 at 05:42

3 Answers3

3

Not sure if it can be done in "pue" LINQ, but a bit of procedural code would do the trick:

var dict = Yours.ToDictionary(y => y.Name);
foreach (var m in Mine) {
    Account y;
    if (dict.TryGetValue(m.Name, out y))
        Ours.Add(new Account { ID = y.ID, Name = m.Name, Value = m.Value });
    else
        Ours.Add(m);
}

After that, printing Ours...

foreach (var o in Ours)
    Console.WriteLine("{0}\t{1}\t{2}", o.ID, o.Name, o.Value);

...gives the following result:

1       C_First joe
2       C_Last  bloggs
        C_Car   ford
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • Is there a way to keep it from adding objects with the same Name and Value?Account m4 = new Account(){ ID = null, Name = "C_Hair", Value = "long" }; Account y3 = new Account(){ ID = "1", Name = "C_Hair", Value = "long" }; – devin M. arnold Oct 31 '13 at 06:35
  • @devinM.arnold If I understood correctly what you wish to accomplish, you'll need to create a "key" class that combines `Name` and `Value`, and then use _it_ as the dictionary key (instead of the string). Just be careful to properly implement [IEquatable](http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx) - override `GetHashCode`. – Branko Dimitrijevic Oct 31 '13 at 06:48
  • adding brackets around the if statement then adding this conditional did the trick (y.Value != m.Value) – devin M. arnold Oct 31 '13 at 06:55
  • that makes perfect sense about creating a separate "key" class, thank you for pointing me in the right direction. cheers! – devin M. arnold Oct 31 '13 at 07:02
0

Try this:

var index = Mine.ToDictionary(x => x.Name);

foreach(var account in Yours)
{
    if(index.ContainsKey(account.Name))
    {
        var item = index[account.Name]; 
        if(item.ID == null)
            item.ID = account.ID;
    }
    index.Add(account.Name, account);
}

Ours = index.Values.ToList();
Ivo
  • 8,172
  • 5
  • 27
  • 42
0

try this code for IEqualityComparer:

public class D : IEqualityComparer<Account>
{
    public bool Equals(Account x, Account y)
    {
        return x.ID == y.ID && x.Value==y.Value;
    }

    public int GetHashCode(Account obj)
    {
        return obj.ID.GetHashCode() ^ obj.Value.GetHashCode();
    }
}

used like this: Ours = Mine.Except(Yours, new D()).ToList();

Grundy
  • 13,356
  • 3
  • 35
  • 55