views:

336

answers:

1

I have run into a situation where I need to compare two different lists to each other and I am wondering what the best method is for doing this? I thought something like this would work but it doesn't and I can't figure out why. The Linq query is returning records it shouldn't. This is my first run at trying to figure something like this out so it is undoubtedly messy.

 private static List<ColumnDefinition> FindTableStructureUpdates(List<ColumnDefinition> colDefs, List<ColumnDefinition> tblCols)
    {
        List<ColumnDefinition> ColsToUpdate = new List<ColumnDefinition>();

        for (int i = 0; i < colDefs.Count; ++i)
        {
            string colDefName = colDefs[i].ColName;
            string colDefDataType = colDefs[i].ColType;
            string colDefAttribute = colDefs[i].ColAttributes;

            var query = from tbl in tblCols
                        where tbl.ColName != colDefName && tbl.ColType != colDefDataType && tbl.ColAttributes != colDefAttribute
                        select new { colDefName, colDefDataType, colDefAttribute };

            if (query.Count() > 0)
            {
                foreach (var item in query)
                {
                    ColsToUpdate.Add(new ColumnDefinition(item.colDefName, item.colDefDataType, item.colDefAttribute));
                }
            }
        }

        return ColsToUpdate;

Any suggestions would be great.

Thanks.

IEquatable Implementation??

 #region IEquatable<ColumnDefinition> Members

    public bool Equals(ColumnDefinition other)
    {
        if (this.ColName.Equals(other.ColName) && this.ColType.Equals(other.ColType) && this.ColAttributes.Equals(other.ColAttributes))
            return true;

        return false;
    }
+2  A: 

Can't you use Enumerable.Except ?

public static IEnumerable<TSource> Except<TSource>(
    this IEnumerable<TSource> first,
    IEnumerable<TSource> second
)

More details.

An example tested in Snippet Compiler

using System;
using System.Linq;
using System.Collections.Generic;

class ColumnDefinition : IEquatable<ColumnDefinition>
{
    public string Name { get; set; }
    public string Type { get; set; }
    public string Attr { get; set; }

    public ColumnDefinition()
    {
     Name = string.Empty;
     Type = string.Empty;
     Attr = string.Empty;
    }

    public bool Equals(ColumnDefinition other)
    { 
     return Name.Equals(other.Name) && Type.Equals(other.Type) && Attr.Equals(other.Attr);
    }

    public override bool Equals(object value)
    {
     return (value is ColumnDefinition) ? Equals(value as ColumnDefinition) : false;
    }

    public override int GetHashCode()
    {
     return Name.GetHashCode() ^ Type.GetHashCode() ^ Attr.GetHashCode();
    }

    public override string ToString()
    {
     return string.Concat("{", Name, ":", Type, ":", Attr, "}");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
     try
     {
      MyMain(args);
     }
     catch (Exception e)
     {
      Console.WriteLine(e);
     }
     finally
     {
      Console.ReadKey();
     }
    }

    public static void MyMain(string[] args)
    {
     var list1 = new []  
      { 
       new ColumnDefinition { Name = "foo", Type = "int", Attr = "0" }, 
       new ColumnDefinition { Name = "bar", Type = "int", Attr = "1" }, 
      };

     var list2 = new [] 
      { 
       new ColumnDefinition { Name = "foo", Type = "int", Attr = "0" }, 
       new ColumnDefinition { Name = "bar", Type = "string", Attr = "1" }, 
      };

     foreach (var changed in Enumerable.Except(list1, list2))
     {
      Console.WriteLine(changed);
     }
    }
}
typeseven
I gave it a shot but it returns records when it shouldn't return anything in my test.
Nathan
Have you implemented a proper equality comparer for your ColumnDefinition class? If not, please do. The Enumerable.Except/Intersect/Union functions depend on it.
typeseven
Oh, I've never done that before. I will give it a shot and see what I come with. Thanks!
Nathan
Typeseven, please see my edit above, is this how I would implement it?
Nathan
Correct, but you also need to override void Equals(object) and int GetHashCode() for the ColumnDefinition class.
typeseven
Since I have three properties do I need to have this line three times, once for each property?int hashProductName = PropertyX == null ? 0 : PropertyX GetHashCode();
Nathan
You may want to factor together the hashcodes for the relevant properties (those used in the equality comparer) such as: return ColName.GetHashCode() ^ ColType.GetHashCode() ^ ColAttributes.GetHashCode();
typeseven
Added an all singing and dancing example =)
typeseven