Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a distinct list of custom type in C#

Tags:

c#

.net

linq

I receive a List of en entity framework type and want to only return the distinct values from the List. I'm using the following approach, however it's not uniquifying the list. Any suggestions?

Param: List<Flag> flags

List<Flag> distinctFlags = flags.Distinct().ToList();

The values of Flag are as follows: ID, Flag, FlagValue. Could I use linq in this instance?

Thanks.

like image 273
stats101 Avatar asked Mar 07 '12 12:03

stats101


2 Answers

Assuming Flag is one of your entity models, you could use a partial class and override Equals and GetHashCode. This also assumes that you have an Id property on on your Flag class which uniquely identities it.

//this namespace MUST match the namespace of your entity model.
namespace Your.Entity.Model.Namespace
{
    public partial class Flag
    {
        public override bool Equals(object obj)
        {
            var item = obj as Flag;

            if (item == null)
            {
                return false;
            }

            return this.Id.Equals(item.Id);
        }

        public override int GetHashCode()
        {
            return this.Id.GetHashCode();
        }
    }
}

Usage would look like this

List<Flag> distinctFlags = allFlags.Distinct().ToList();
like image 58
Craig Avatar answered Oct 31 '22 22:10

Craig


Probably flags is a list of reference type, and distinct does not work as you expect! This because Distinct() work not on the value of the flag in the list, but on its memory references (that are all differents).

You have to write a comparer class that teach to Distinct how to compare equal flag. Suppose you have this flag class:

public class flag
{ 
    public string Name { get; set; }
    public string Code { get; set; }
}

you should create a comparer class like this:

class FlagComparer : IEqualityComparer<flag>
{
    // Products are equal if their names and product numbers are equal.
    public bool Equals(flag x, flag y)
    {

        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the products' properties are equal.
        return x.Code == y.Code && x.Name == y.Name;
    }
}

and the call your statement:

List distinctFlags = flags.Distinct(new FlagComparer ()).ToList();

In this way, Distinct method know exactly how to compare equals flag istance.

UPDATE

Based on your comment, if you wanto to follow my suggestion, you should write the comparer base as follow:

class FlagComparer : IEqualityComparer<flag>
    {
        // Products are equal if their names and product numbers are equal.
        public bool Equals(flag x, flag y)
        {

            //Check whether the compared objects reference the same data.
            if (Object.ReferenceEquals(x, y)) return true;

            //Check whether any of the compared objects is null.
            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                return false;

            //Check whether the products' properties are equal.
            return x.HostID == y.HostID && x.RuleID == y.RuleID && x.Flag == y.Flag && x.FlagValue == y.FlagValue;
        }
    }

Of course, every property must be a value type.

Take a look here to clarify yourself:

  • Value Type
  • Reference type
like image 26
AngeloBad Avatar answered Oct 31 '22 23:10

AngeloBad