2014-02-10 4 views
9

У меня есть список пользовательского типа данные, упрощенный пример (myMovies):Выберите отличие от списка <t> игнорируя один элемент

public class Movie 
{ 
    public Int32 TVIndex; 
    public string MovieName; 
    public string MovieRating; 
    public string MovieRuntime; 
    public List<Actor> MovieActors; 
    public List<MovieArt> MovieImages; 
} 



public class Actor 
{ 
    public string ActorName; 
    public string ActorRole; 
} 

public class MovieArt 
{ 
    public string ImagePath; 
} 


List<Movie> myMovies = new List<Movie>(); 

Теперь я пытаюсь удалить все дубликаты из myMovies но игнорируя TVIndex.

Я пытался смотреть на

List<Movie> myDistinctMovies = myMovies.Distinct().ToList(); 

Но не могу понять, как игнорировать TvIndex. Это возможно?

+3

вы можете использовать [Distinct с EqualityComparer] (http://msdn.microsoft.com/ ru-ru/library/bb338049 (v = vs.110) .aspx) – Grundy

+4

Вы можете переопределить Equals и GetHashCode типа данных Movie. – Peter

+1

@ Grundy/peer .. Пример будет отличным .. –

ответ

3

На основе @ ответ Гранди, в том числе реализации:

public class MovieEqualityComparer : IEqualityComparer<Movie> 
{ 

    public bool Equals(Movie x, Movie y) 
    { 
     if (x == null) 
      return y == null; 

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

     if (object.ReferenceEquals(x, y)) 
      return true; 

     if (!string.Equals(x.MovieName, y.MovieName)) 
      return false; 

     if (!string.Equals(x.MovieRating, y.MovieRating)) 
      return false; 

     if (!string.Equals(x.MovieRuntime, y.MovieRuntime)) 
      return false; 

     if (!Enumerable.SequenceEqual(x.MovieActors, y.MovieActors)) 
      return false; 

     if (!Enumerable.SequenceEqual(x.MovieImages, y.MovieImages)) 
      return false; 

     return true; 
    } 

    public int GetHashCode(Movie obj) 
    { 
     if (obj == null) 
      throw new ArgumentNullException(); 

     unchecked 
     { 
      int hash = 17; 
      hash  = hash * 31 + ((obj.MovieName == null) ? 0 : obj.MovieName.GetHashCode()); 
      hash  = hash * 31 + ((obj.MovieRating == null) ? 0 : obj.MovieRating.GetHashCode()); 
      hash  = hash * 31 + ((obj.MovieRuntime == null) ? 0 : obj.MovieRuntime.GetHashCode()); 

      if (obj.MovieActors != null) 
      { 
       foreach (var actor in obj.MovieActors) 
        hash = hash * 31 + ((actor == null) ? 0 : actor.GetHashCode()); 
      } 

      if (obj.MovieImages != null) 
      { 
       foreach (var image in obj.MovieImages) 
        hash = hash * 31 + ((image == null) ? 0 : image.GetHashCode()); 
      } 

      return hash; 
     } 
    } 
} 

Использование является тем же самым:

List<Movie> myMovies = new List<Movie> 
    { 
     // ... 
    }; 

List<Movie> myDistinctMovies = myMovies.Distinct(new MovieEqualityComparer()).ToList(); 

EDIT

Как отметил @ Тим, вы должны сделать что-то очень похожее на других ваших пользовательских типов, если вы хотите сравнить ничем, кроме равенство ссылок.

public class Actor : IEquatable<Actor> 
{ 
    public string ActorName; 
    public string ActorRole; 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as Actor); 
    } 

    public bool Equals(Actor other) 
    { 
     if (other == null) 
      return false; 

     if (object.ReferenceEquals(this, other)) 
      return true; 

     if (!string.Equals(this.ActorName, other.ActorName)) 
      return false; 

     if (!string.Equals(this.ActorRole, other.ActorRole)) 
      return false; 

     return true; 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 
      hash  = hash * 31 + ((ActorName == null) ? 0 : ActorName.GetHashCode()); 
      hash  = hash * 31 + ((ActorRole == null) ? 0 : ActorRole.GetHashCode()); 

      return hash; 
     } 
    } 
} 

public class MovieArt : IEquatable<MovieArt> 
{ 
    public string ImagePath; 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as MovieArt); 
    } 

    public bool Equals(MovieArt other) 
    { 
     if (other == null) 
      return false; 

     if (object.ReferenceEquals(this, other)) 
      return true; 

     if (!string.Equals(this.ImagePath, other.ImagePath)) 
      return false; 

     return true; 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = 17; 
      hash  = hash * 31 + ((ImagePath == null) ? 0 : ImagePath.GetHashCode()); 

      return hash; 
     } 
    } 
} 
+0

в 'GetHashCode', возможно, потребуется добавить check для значения свойства null, – Grundy

+0

@Grundy Я изменил алгоритм :) –

+0

yep! что я имею в виду. Но какие магические цифры '17' и' 31'? – Grundy

2

вы можете использовать Distinct with EqualityComparer что-то вроде этого

public class MoviesEqualityComparer : IEqualityComparer<Movie> 
{ 
    public bool Equals(Movie x, Movie y) 
    { 
     return ..../* check all needed fields */ 

    } 

    public int GetHashCode(Movie obj) 
    { 
     return .... /* get hashcode for movie objec*/ 
    } 
} 

и использовать его как

List<Movie> myDistinctMovies = myMovies.Distinct(new MoviesEqualityComparer()).ToList(); 
+2

Сложность - это реализация;) –

+0

@TimSchmelter yep, если нужно игнорировать только одно поле. Возможно использование группировки будет простейшим – Grundy

-1

вы можете использовать LINQ запрос может быть ...

List<Movie> myDistinctMovies = (myMovies .GroupBy(p =>p.MovieName, 
                p =>p.MovieRating,p=>p.MovieRuntime) 
              .Select(g => g.First()) 
              .ToList()); 

Спасибо ..

+0

Это мое личное предпочтение, потому что для этого не требуется создание IEqualityComparer (yuck). – Hezi

+0

Спасибо, я чувствую, что это проще и точнее! – rawatdeepesh

+1

Но это игнорирует рейтинг, время исполнения, актеры и изображения. -1 –

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