0

I have a list of items, and i try to getting unique items by distinct keys. The class:

class TempClass
    {
        public string One { get; set; }
        public string Two { get; set; }
        public string Key
        {
            get
            {
                return "Key_" + One + "_" + Two;
            }
        }
    }    

I build the dummy list as follows:

List<TempClass> l = new List<TempClass>()
        {
            new TempClass(){ One="Da" , Two = "Mi"},
            new TempClass(){ One="Da" , Two = "Mi"},
            new TempClass(){ One="Da" , Two = "Mi"},
            new TempClass(){ One="Mi" , Two = "Da"},
            new TempClass(){ One="Mi" , Two = "Da"},
        };

My question is - how get only 1 item? by check that does exist only unique key? unique item means that should to check that have there only one key that equals to "Key_Da_Mi" or "Key_Mi_Da"?

how to achieve that?

David Michaeli
  • 367
  • 5
  • 26

3 Answers3

1

Group each of the items on a HashSet of strings containing both keys, use HashSet's set comparer to compare the items as sets (sets are unordered) and then pull out the first (or whichever) item from each group:

var distinct = l.GroupBy(item => new HashSet<string>() { item.One, item.Two },
        HashSet<string>.CreateSetComparer())
    .Select(group => group.First());
Servy
  • 202,030
  • 26
  • 332
  • 449
0

You should either implement equality comparison, or implement IEqualityComparer<T> with your specific logic:

class TempClassEqualityComparer : IEqualityComparer<TempClass>
{
    public bool Equals(TempClass x, TempClass y)
    {
        if (Object.ReferenceEquals(x, y)) return true;

        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        // For comparison check both combinations
        return (x.One == y.One &&  x.Two == y.Two) || (x.One == y.Two && x.Two == y.One);
    }

    public int GetHashCode(TempClass x)
    {
        if (Object.ReferenceEquals(x, null)) return 0;

        return x.One.GetHashCode() ^ x.Two.GetHashCode();
    }
}

Then you can use this comparer in Distinct method:

var result = l.Distinct(new TempClassEqualityComparer());
dotnetom
  • 24,551
  • 9
  • 51
  • 54
  • 1
    There's no reason to order the hash codes before XORing them together. It's a commutative operation. – Servy Feb 17 '15 at 17:18
-1

Just order them before you create the key.

public string Key
{
  get{
    List<string> l = new List<string>{One, Two};
    l = l.OrderBy(x => x).ToList();
    return "Key_" + string.Join("_", l);
  }
}
Kyle W
  • 3,702
  • 20
  • 32
  • Using this approach `{"a", "bc"}` would be equal to `"ab", "c"`, even though they're actually different. – Servy Feb 17 '15 at 17:13
  • No, it's not. He wants `"a" "b"` to be equal to `"b", "a"` – Servy Feb 17 '15 at 17:14
  • No it wouldn't, the key values are separated by "_" – Kyle W Feb 17 '15 at 17:14
  • That just makes it a bit more awkward. {"a_b", "c"} would be equal to {"a", "b_c"} – Servy Feb 17 '15 at 17:15
  • Yes and that's the way he was doing it before, so since making sure that it's not part of his dataset was not part of his question, I'll leave it as is. – Kyle W Feb 17 '15 at 17:17