Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if an object already exists in collection

Tags:

c#

equality

list

I am learning programming and my problem is that I have a bunch of objects and I want to add these objects to a list only if the list does not already contain that object. Secondly if the object is already contained I want to ignore that object and add the next one instead. I think I have got the first part working just need some help with part two. Many thanks.

PartyGroup partyGroup = new PartyGroup(); 

using (AseDataReader reader = command.ExecuteReader()) 
{ 
    while (reader.Read()) 
    {  
        if (!myPartyGroupList.Contains(partyGroup)) 
        { 
            partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]); 
            partyGroup.PartyGroupName = reader["party_group_name"].ToString(); 
            partyGroup.PersonList = myPersonList; 

            myPartyGroupList.Add(partyGroup); 
        } 
        else 
        { 
            //?? 
        } 
    } 
} 
like image 340
Ben Avatar asked Dec 17 '10 21:12

Ben


3 Answers

You've got the first part down perfect.

Just remove the 'else' clause and your routine will automatically add the next element in the next iteration. Like this:

while (reader.Read()) 
{ 
    if (!myPartyGroupList.Contains(partyGroup)) 
    { 
        partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]); 
        partyGroup.PartyGroupName = reader["party_group_name"].ToString(); 
        partyGroup.PersonList = myPersonList; 

        myPartyGroupList.Add(partyGroup); 

    } 
} 
like image 76
Flipster Avatar answered Nov 15 '22 04:11

Flipster


Your code has some issues. First, you're reusing the same object for each of your iterations.

Consider

List<Foo> foos = new List<Foo>();
Foo foo = new Foo();
foo.Bar = "Alpha";
foos.Add(foo);
foo.Bar = "Beta";
foos.Add(foo);

You will note that your list will have 2 items but they will reference the same object. If you iterate over the list and check Bar, each will return "Beta".

You want to create a new Foo for each item.

List<Foo> foos = new List<Foo>();
Foo foo = new Foo();
foo.Bar = "Alpha";
foos.Add(foo);
Foo anotherFoo = new Foo();
anotherFoo.Bar = "Beta";
foos.Add(anotherFoo);

In looping terms, that basically just means create the object inside the loop instead of outside.

while (someCondition)
{
    Foo foo = new Foo();
    // do your work, populate the object, etc.
    // then check contains 
    if (!myList.Contains(foo))
        myList.Add(foo);
}

Regarding checking to see if the collection already contains the object, have you properly overriden Equals and GetHashCode? When dealing the classes, the default behavior is to simply check if the object references are equal. If you're concerned about the values the objects are encapsulating, then you need to provide the logic for that yourself. In your class, you need to override the Equals and GetHashCode methods to implement your desired method of determining equality.

class Foo
{
    public string Bar { get; set; }

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

    public override bool Equals(object other)
    {
        Foo otherFoo = other as Foo;
        if (otherFoo == null)
            return false;
        else
            return this.Bar == otherFoo.Bar;
    }
}

Now when Contains seeks to determine if the object is already in the list, it will do so based upon the the values contained in the object rather than the memory reference.

like image 4
Anthony Pegram Avatar answered Nov 15 '22 03:11

Anthony Pegram


When comparing it is better to use comparison with respect to a identifier, which in your case is the PartyGroupId. If you use contains then the default overload of Contains() then the hash value of the object in the list is used for comparison.

So rather than leave the comparison to .NET you can create a custom IEqualityComparer implementation or use Linq's Where clause as follows.


using (AseDataReader reader = command.ExecuteReader()) 
{ 
    while (reader.Read()) 
    {  
        int groupId = Convert.ToInt32(reader["party_group_id"]);

        if (partyGroupsList.Where(partyGroup => partyGroup.PartyGroupID == groupId).Any() == false)
        {
           PartyGroup newPartyGroup = new PartyGroup()
                                      {
                                          PartyGroupID = groupId,
                                          PartyGroupName = reader["party_group_name"].ToString(),
                                          PersonList = myPersonList
                                      };

           partyGroupsList.Add(newPartyGroup);                 
        } 

        // If object already exists in the list then do not add, continue 
        // to the next row.   
    } 
} 

Another suggestion is to rename to PartyGroup class members as:


class PartyGroup
 {
   public int ID { get; set; }
   public string Name { get; set; }
   public IList PersonList { get; set; }
}
like image 3
Devendra D. Chavan Avatar answered Nov 15 '22 04:11

Devendra D. Chavan