4

When I use the following code I get the same items multiple times.

XElement neededFiles = new XElement("needed",
    from o in _9nFiles.Elements()
    join t in addedToSitePull.Elements()
         on o.Value equals
         t.Value
    where o.Value == t.Value
    select new XElement("pic", o.Value));

I'd like to get only unique items. I saw a Stack Overflow post, How can I do SELECT UNIQUE with LINQ?, that used it, and I tried to implement it, but the change had no affect.

The code:

XElement neededFiles = new XElement("needed",
(from o in _9nFiles.Elements()
join t in addedToSitePull.Elements()
on o.Value equals
 t.Value
 where o.Value == t.Value
select new XElement("pic", o.Value)).Distinct() );
Community
  • 1
  • 1
Asaf
  • 3,067
  • 11
  • 35
  • 54

3 Answers3

7

I imagine the reason this doesn't work is because XElement.Equals uses a simple reference equality check rather than comparing the Value properties of the two items. If you want to compare the values, you could change it to:

_9nfiles.Elements()
    .Join(addedToSitePull, o => o.Value, t => t.Value, (o, t) => o.Value)
    .Distinct()
    .Select(val => new XElement("pic", val));

You could also create your own IEqualityComparer<T> for comparing two XElements by their values. Note this assumes all values are non-null:

public class XElementValueEqualityComparer : IEqualityComparer<XElement>
{
    public bool Equals(XElement x, XElement y)
    {
        return x.Value.Equals(y.Value);
    }

    public int GetHashCode(XElement x)
    {
        return x.Value.GetHashCode();
    }
}

Then you could replace the existing call to Distinct with Distinct(new XElementValueEqualityComparer()).

Lee
  • 142,018
  • 20
  • 234
  • 287
  • +1 despite the fact that I had to implement a bad solution due to time issues ,I'm looking forward to test and learn your solution - thanks Asaf – Asaf Sep 16 '10 at 15:22
4

Distinct doesn't work because XElements are compared by reference, not by value. The solution is to use another overload of Distinct - Distinct(IEqualityComparer);

You need to implement IEqualityComparer for example as follows:

class XElementEqualityComparer : IEqualityComparer<XElement>
    {
        #region IEqualityComparer<XElement> Members

        public bool Equals(XElement x, XElement y)
        {
            if (x == null ^ y == null)
                return false;

            if (x == null && y == null)
                return true;

            return x.Value == y.Value;
        }

        public int GetHashCode(XElement obj)
        {
            if (obj == null)
                return 0;

            return obj.Value.GetHashCode();
        }

        #endregion
    }
ILya
  • 2,670
  • 4
  • 27
  • 40
0

It's not a good solution - but really easy.

foreach (XElement  pic in neededFiles.Elements())
{
    unSyncedPictures.Add(pic.Value);
}
List<string> temp = new List<string>();
temp.AddRange(unSyncedPictures.Distinct());
Asaf
  • 3,067
  • 11
  • 35
  • 54