Check if an object exists in the collection

I am learning programming, and my problem is that I have a bunch of objects, and I want to add these objects to the list only if this list does not already contain this object. Secondly, if the object is already contained, I want to ignore this object and add the following instead. I think I have the first part of the work, which just needs some help with the second part. Thank you very much.

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 { //?? } } } 
+4
source share
6 answers

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

Therefore, instead of leaving a comparison with .NET, you can create a custom implementation of IEqualityComparer or use the Linq 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; } } 
+3
source

You have the first beautiful part.

Just remove the "else" clause and your routine will automatically add the next element to 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); } } 
+5
source

There are some problems in your code. First, you reuse the same object for each iteration.

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 notice that your list will contain 2 elements, but they will refer to the same object. If you iterate over the list and check the Bar , each returns "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 cyclic terms, this basically means creating an object inside a loop instead of an external one.

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

As for checking if the collection already contains an object, are you overriding Equals and GetHashCode correctly? When working with classes, the default behavior is to simply check if the references to the objects are equal. If you are worried about the values ​​that objects encapsulate, then you need to provide logic for yourself. In your class, you need to override the Equals and GetHashCode methods to implement the desired method for 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 tries to determine if an object is in the list, it will do this based on the values ​​contained in the object, not the memory reference.

+4
source

You might want to use the Hashset<PartyGroup> to populate and then convert it to a list. If you have a large number of items, this will be significantly faster than checking the list for each item.

 Hashset<PartyGroup> pgHash = new Hashset<PartyGroup>(); using (AseDataReader reader = command.ExecuteReader()) { while (reader.Read()) { PartyGroup pg = new PartyGroup(); partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]); partyGroup.PartyGroupName = reader["party_group_name"].ToString(); partyGroup.PersonList = myPersonList; // Add won't add an item if it already exists in the collection. pgHash.Add(partyGroup); } } // Now convert the result to a list. myPartyGroupList = pgHash.ToList(); 

If your PartyGroup class PartyGroup not implement IEquatable<PartyGroup> , you need to provide an equality IEquatable<PartyGroup> . The following should work:

 public class PartyGroupComparer:IEqualityComparer<PartyGroup> { public bool Equals(PartyGroup g1, PartyGroup g2) { return g1.PartyGroupId.Equals(g2.PartyGroupId); } public int GetHashCode(PartyGroup g) { return g.PartyGroupId; } } 

And then your initialization will look like this:

 IEqualityComparer<PartyGroup> pgComparer = new PartyGroupComparer(); HashSet<PartyGroup> pgHash = new HashSet<PartyGroup>(pgComparer); 

An alternative to HashSet , as another pointed out, is Dictionary . This will prevent you from doing an equality mapping. You still have to convert to a list when you're done. But this is pretty easy:

 Dictionary<int, PartyGroup> dict = new Dictionary<int, PartyGroup>(); // populate dictionary as suggested in other answer // now convert values to a list. myPartyGroupList = dict.Values.ToList(); 
+1
source

try it

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

First you check to see if an instance of the object is in the collection, but you create one instance once (outside the while loop). So when you check if !myPartyGroupList.Contains(partyGroup) , it will return false the first time, so you add obj to the collection, and then it will return false every time.

I would use a dictionary using the Id property as the dictionary key.

like this:

 Dictionary <int,PartyGroup> myPartyGroupList = new Dictionary <int,PartyGroup>(); using (AseDataReader reader = command.ExecuteReader()) { while (reader.Read()) { int id=Convert.ToInt32(reader["party_group_id"]); if (!myPartyGroupList.ContainsKey( id )) { PartyGroup partyGroup = new PartyGroup(); partyGroup.PartyGroupID = id; partyGroup.PartyGroupName = reader["party_group_name"].ToString(); partyGroup.PersonList = myPersonList; myPartyGroupList.Add(id, partyGroup); // key, value? check param order here } } } 
0
source

Source: https://habr.com/ru/post/1332553/


All Articles