0

I have a class which has 3 properties and when it's being evaluated for equality, I only want 2 of them be accounted for. That means, in the following Product class, Misc should have no role in equality comparison.

However, when the code runs, only apple 9 a is displayed. But I also want apple 9 b be displayed too. So what is wrong in the code?

namespace ConsoleApplication1
{
    public class Product
    {
        public string Name { get; set; }
        public int Code { get; set; }
        public string Misc { get; set; }
    }

    class ProductComparer : IEqualityComparer<Product>
    {
        public bool Equals(Product x, Product y)
        {
            if (Object.ReferenceEquals(x, y)) return true;
            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false;

            return x.Code == y.Code && x.Name == y.Name;
        }

        public int GetHashCode(Product product)
        {
            if (Object.ReferenceEquals(product, null)) return 0;
            int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();
            int hashProductCode = product.Code.GetHashCode();

            return hashProductName ^ hashProductCode;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            Product[] store1 = { new Product { Name = "apple", Code = 9, Misc = "a" }, 
                                 new Product { Name = "orange", Code = 4 , Misc = "c"} };

            Product[] store2 = { new Product { Name = "apple", Code = 9, Misc = "b" }, 
                                 new Product { Name = "lemon", Code = 12, Misc = "d" } };

            IEnumerable<Product> duplicates = store1.Intersect(store2, new ProductComparer());

            foreach (var product in duplicates)
                Console.WriteLine(product.Name + " " + product.Code + " " + product.Misc);


            Console.Read();
        }
    }
}
Ray Cheng
  • 12,230
  • 14
  • 74
  • 137

3 Answers3

2

To get the intersection of the two sets but to get the item from both sets, rather than just one of the matches, you'll need to use a Join. Intersect is just a special case of Join, you simply want to project the results of your matches into both results, rather than just one:

var duplicates = store1.Join(store2,
    p => p,
    p => p,
    (a, b) => new[] { a, b },
    new ProductComparer())
    .SelectMany(p => p);
Servy
  • 202,030
  • 26
  • 332
  • 449
1

The reason why apple 9 b does not appear in the duplicates is that according to your Comparer, apple 9 b is same as apple 9 a. The result of Intersect only contains distinct values.

sean717
  • 11,759
  • 20
  • 66
  • 90
  • I see, so I'll need inner join then. Correct? – Ray Cheng Oct 24 '14 at 05:05
  • if this is not for a technical interview...I think it is ok just to use a for loop and contains(). – sean717 Oct 24 '14 at 05:43
  • I found this one works for me and also generic enough. http://stackoverflow.com/questions/716552/can-you-create-a-simple-equalitycomparert-using-a-lamba-expression/716647#716647 – Ray Cheng Oct 24 '14 at 18:27
0

You could find the duplicates again:

foreach (var product in store1.Concat(store2).Where(p => duplicates.Contains(p, new ProductComparer())))
    Console.WriteLine(product.Name + " " + product.Code + " " + product.Misc);
Dmitry
  • 13,797
  • 6
  • 32
  • 48