Chatwa
Chatwa

Reputation: 11

Remove and get duplicates in a list in C#

I have a list which consists of the following properties:

public class Category 
{    
   public int RecordId { get; set;}
   public string Category { get; set;}
   public Data DataObj { get; set;}
}

My list is defined as List<Category> categories.

The data class holds the following properties:

{
   Id: 1,
   Name: "Smith",
   Input: "7,8",
   Output: "Output1",
   CreatedBy: "swallac",
   CreatedON: "12/01/2018"
},
{
   Id: 3,
   Name: "Austin",
   Input: "9,10",
   Output: "Output1",
   CreatedBy: "amanda",
   CreatedON: "12/03/2018"
},
{
   Id: 2,
   Name: "Austin",
   Input: "9,10",
   Output: "Output1",
   CreatedBy: "amanda",
   CreatedON: "12/03/2018"
}

How can I get the duplicate item in the Data object?

I have tried the following but does not seem to return me the correct results.

 var categoriesFiltered = categories.Select(g => g.DataObj);

 var duplicateDataa = categoriesFiltered.GroupBy(x => x)
                                     .Where(g => g.Count() > 1)
                                     .Select(y => y.Key);

Upvotes: 1

Views: 123

Answers (2)

Bizhan
Bizhan

Reputation: 17085

You can use an Equality Comparer:

    class MyComparer : IEqualityComparer<Category>
    {
        public bool Equals(Category? x, Category? y)
        {
            return x?.DataObj.Name == y?.DataObj.Input &&
                   x?.DataObj.Input == y?.DataObj.Input &&
                   x?.DataObj.Output == y?.DataObj.Output;
        }

        public int GetHashCode(Category obj)
        {
            return obj.DataObj.Name.GetHashCode() +
                   obj.DataObj.Input.GetHashCode() +
                   obj.DataObj.Output.GetHashCode();
        }
    }

Then use that comparer to make a distinction between your items:

 var distinctList = categoriesFiltered.Distinct(new MyComparer());

Alternatively you can implement IEquatable<T> on any class that needs to be compared in an arbitrary way:

    public class Category : IEquatable<Category>
    {
        public int RecordId { get; set;}
        public string Category { get; set;}
        public Data DataObj { get; set;}

        public bool Equals(Category? other)
        {
            return DataObj.Equals(other?.DataObj);
        }
    }
    public class Data : IEquatable<Data>
    {
        ...
        public bool Equals(Data? other)
        {
            return Name.Equals(other?.Name) && Input.Equals(other?.Input) && ...;
        }
    }

Then let C# use them:

 var distinctList = categoriesFiltered.Distinct();

If you want to know which items are removed as duplicate you can use Except:

 duplicates = categoriesFiltered.Except(distinctList);

Upvotes: 2

JonasH
JonasH

Reputation: 36341

You are probably lacking a equalitycomparer.

Since Category is a class without an equals method it will default to reference equality. There are several ways to define equality of objects.

  1. Create a new class, implementing IEqualityComparer<Category>, use this class as input to your Distinct call. This allow multiple different ways to compare the same type.
  2. Let Category Implement IEquatable<Category>
  3. Override Equals(object) method.

Upvotes: 1

Related Questions