Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select distinct from List<t> ignoring one element

Tags:

c#

list

linq

I have a List of custom a datatype, simplified example (myMovies):

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>(); 

Now I am trying to remove all duplicates from myMovies but ignoring TVIndex.

I have tried looking at

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

But cannot figure out how to ignore TvIndex. Is this possible?

like image 582
Fred Avatar asked Feb 10 '14 12:02

Fred


People also ask

What is distinct () in C#?

C# Linq Distinct() method removes the duplicate elements from a sequence (list) and returns the distinct elements from a single data source. It comes under the Set operators' category in LINQ query operators, and the method works the same way as the DISTINCT directive in Structured Query Language (SQL).

How do I get distinct data from a list?

To get unique elements. List<int> myList = list. Distinct(). ToList();

How do I get distinct on a single column in LINQ?

distinct in Linq to get result based on one field of the table (so do not require a whole duplicated records from table). I know writing basic query using distinct as followed: var query = (from r in table1 orderby r. Text select r).

How does Linq distinct work?

LINQ Distinct operator removes all the duplicate values from the collection and finally returns the dissimilar or unique values. The LINQ Distinct operator available in only Method Syntax and it not supports the Query Syntax. LINQ Distinct is an operator which comes under Set Operator.


2 Answers

Based on @Grundy's answer, including implementation:

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;
        }
    }
}

Usage is the same:

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

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

EDIT

As pointed out by @Tim, you have to do something quite similar for your other custom types if you want to compare by anything other than reference equality.

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;
        }
    }
}
like image 126
Steven Liekens Avatar answered Oct 06 '22 19:10

Steven Liekens


you can use Distinct with EqualityComparer something like this

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*/
    }
}

and use it like

List<Movie> myDistinctMovies = myMovies.Distinct(new MoviesEqualityComparer()).ToList(); 
like image 43
Grundy Avatar answered Oct 06 '22 19:10

Grundy