2015-06-16 7 views
2

Существует очень простой класс:Distinct() Как найти уникальные элементы в списке объектов

public class LinkInformation 
{ 
    public LinkInformation(string link, string text, string group) 
    { 
     this.Link = link; 
     this.Text = text; 
     this.Group = group; 
    } 

    public string Link { get; set; } 
    public string Text { get; set; } 
    public string Group { get; set; } 

    public override string ToString() 
    { 
     return Link.PadRight(70) + Text.PadRight(40) + Group; 
    } 
} 

И создать список объектов этого класса, содержащий несколько дубликатов.

Итак, я попытался использовать Distinct(), чтобы получить список уникальных значений.

Но это не работает, поэтому я реализовал

IComparable<LinkInformation> 

    int IComparable<LinkInformation>.CompareTo(LinkInformation other) 
    { 
     return this.ToString().CompareTo(other.ToString()); 
    } 

, а затем ...

IEqualityComparer<LinkInformation> 

    public bool Equals(LinkInformation x, LinkInformation y) 
    { 
     return x.ToString().CompareTo(y.ToString()) == 0; 
    } 

    public int GetHashCode(LinkInformation obj) 
    { 
     int hash = 17; 
     // Suitable nullity checks etc, of course :) 
     hash = hash * 23 + obj.Link.GetHashCode(); 
     hash = hash * 23 + obj.Text.GetHashCode(); 
     hash = hash * 23 + obj.Group.GetHashCode(); 
     return hash; 
    } 

код с помощью Distinct является:

static void Main(string[] args) 
    { 
     string[] filePath = { @"C:\temp\html\1.html", 
           @"C:\temp\html\2.html", 
           @"C:\temp\html\3.html", 
           @"C:\temp\html\4.html", 
           @"C:\temp\html\5.html"}; 

     int index = 0; 

     foreach (var path in filePath) 
     { 
      var parser = new HtmlParser(); 

      var list = parser.Parse(path); 

      var unique = list.Distinct(); 

      foreach (var elem in unique) 
      { 
       var full = new FileInfo(path).Name; 
       var file = full.Substring(0, full.Length - 5); 
       Console.WriteLine((++index).ToString().PadRight(5) + file.PadRight(20) + elem); 
      } 
     } 

     Console.ReadKey(); 
    } 

Что должно быть сделано, чтобы получить Distinct()?

+1

Показать запрос '.Distinct() – maksymiuk

+0

Можете ли вы показать реализацию Equal и GetHashCode в первую очередь? –

+0

Вы передали свой 'IEqualityComparer' на вызов' Distinct'? – Servy

ответ

5

Вы должны фактически передать IEqualityComparer, что вы создали для Disctinct, когда вы назови это. Он имеет две перегрузки, один не принимает никаких параметров и один принимает IEqualityComparer. Если вы не предоставляете сопоставитель, используется значение по умолчанию, а сопоставитель по умолчанию не сравнивает объекты по своему усмотрению.

+0

Да, вот оно! Спасибо огромное! –

+0

Итак, есть ли способ сделать сам класс отличным? –

+1

@MareInfinitus Если класс должен иметь возможность сравнивать себя для равенства и не требует отдельного компаратора, тогда пусть он реализует 'IEquatable' или переопределяет' object.Equals', а также переопределяет 'object.GetHashCode'. Это повлияет на поведение сравнения по умолчанию. – Servy

1

Если вы хотите вернуть отдельные элементы из последовательностей объектов определенного типа данных, вам необходимо реализовать универсальный интерфейс IEquatable в классе.

вот пример реализации:

public class Product : IEquatable<Product> 
{ 
    public string Name { get; set; } 
    public int Code { get; set; } 

    public bool Equals(Product other) 
    { 

     //Check whether the compared object is null. 
     if (Object.ReferenceEquals(other, null)) return false; 

     //Check whether the compared object references the same data. 
     if (Object.ReferenceEquals(this, other)) return true; 

     //Check whether the products' properties are equal. 
     return Code.Equals(other.Code) && Name.Equals(other.Name); 
    } 

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects. 

    public override int GetHashCode() 
    { 

     //Get hash code for the Name field if it is not null. 
     int hashProductName = Name == null ? 0 : Name.GetHashCode(); 

     //Get hash code for the Code field. 
     int hashProductCode = Code.GetHashCode(); 

     //Calculate the hash code for the product. 
     return hashProductName^hashProductCode; 
    } 
} 

И это, как вы делаете фактическое отличие:

Product[] products = { new Product { Name = "apple", Code = 9 }, 
         new Product { Name = "orange", Code = 4 }, 
         new Product { Name = "apple", Code = 9 }, 
         new Product { Name = "lemon", Code = 12 } }; 

//Exclude duplicates. 

IEnumerable<Product> noduplicates = 
    products.Distinct(); 
+0

Это тоже не работает ... –

+2

Один из них * не * должен иметь объекты, реализующие 'IEquatable'. Создание «IEqualityComparer» также прекрасное, как переопределение «Equals» и «GetHashCode» без 'IEquatable'. У ОП уже есть 'IEqualityComparer', поэтому этот маршрут отлично подходит. – Servy

+0

Несмотря на это, это не сработает. Но мне действительно понравилось бы реализовать класс, чтобы он работал с Distinct из коробки, без необходимости внедрять больше классов. –

1

Если вы счастливы с определением «отчетливость» по одному свойству, вы можете сделать

list 
    .GroupBy(x => x.Text) 
    .Select(x => x.First()) 

, чтобы получить список «уникальных» элементов.

Не нужно возиться с IEqualityComparer и др.

+0

He * не * имеет одно свойство как идентификатор объекта. Он использует три. – Servy

+0

Итак, вы посмотрели фактические данные? ;-) –

+0

Один из них, «Ссылка» будет уникальным. Таким образом, ваш способ действительно работает, несмотря на то, что он не использует Distinct ... но здесь это не проблема. Спасибо! –

1

без использования Distinct, ни в компаратор, как насчет:

list.GroupBy(x => x.ToString()).Select(x => x.First()) 

Я знаю, что это решение не является ответом на точный вопрос, но я думаю, что справедливо будет открыт для других решений.

+0

какая хорошая идея! Никогда об этом не думал! –

+1

Нет смысла делать это, так как вы получите такое же поведение с помощью 'list.GroupBy (x => x.ToString()). Выберите (x => x.First());'. Не нужно воссоздавать объект из ключа/'ToString()', то есть. –

+0

Вы правы Christoffer, я изменю свое сообщение спасибо – fradique

Смежные вопросы