2

In C# I'm trying to create a list of objects and when a new thing is added to the list, it is checked to make sure the same ID isn't used. I have the solution in Linq but I'm trying to do it without linq.

public void AddStudent(Student student)
        {
            if (students == null)                               
            {
                students.Add(student);                          
            }
            else
            {
                if ((students.Count(s => s.Id == student.Id)) == 1)   

                  // LINQ query, student id is unique
            {
                throw new ArgumentException("Error student " 
                  + student.Name + " is already in the class");
            }
            else
            {
                students.Add(student);
            }
        }
    }
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Robert Pallin
  • 129
  • 2
  • 3
  • 11

8 Answers8

5

Another approach would be to use a HashSet instead of a List.

The Student class:

public class Student
{
    private int id;

    public override int GetHashCode()
    {
        return this.id;
    }
    public override bool Equals(object obj)
    {
        Student otherStudent = obj as Student;
        if (otherStudent !=null)
        {
            return this.id.Equals(otherStudent.id);
        }
        else
        {
            throw new ArgumentException();
        }

    }

    public int Id
    {
        get { return id; }
        set { id = value; }
    }

}

Then you can add stuff like this

    HashSet<Student> hashSetOfStudents = new HashSet<Student>();
    Student s1 = new Student() { Id = 1 };
    Student s2 = new Student() { Id = 2 };
    Student s3 = new Student() { Id = 2 };

    hashSetOfStudents.Add(s1);
    hashSetOfStudents.Add(s2);
    hashSetOfStudents.Add(s3);

The addition of s3 will fail because it has the same Id as s2.

Brad
  • 11,934
  • 4
  • 45
  • 73
2

You can override Student.Equals() and Student.GetHashCode() to check if the Student.Id is equal. If the student list inherits from List<Student>, you can just use the default Add() method. It will only add students with different Ids.

public class Student
{
    // ...

    public override bool Equals(object obj)
    {
        // Check for null values and compare run-time types.
        if (obj == null || GetType() != obj.GetType()) 
            return false;

        Student other = obj as Student;
        return this.Id == other.Id;
    }

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

public class StudentList : List<Student> { }

// Usage:

var students = new StudentList();
students.Add(student);
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
1

A list of distinct items sounds awfully lot like a set

Update: Writing up a good motivation for how to select proper datastructures got a bit tedious, I'll just show you how you will write the above once you are more familiar with the .NET framework:

public void AddStudent(Student student)
{
    /* this.students is an ISet<Student> */
    if (!this.students.Add(student))
    {
       throw new ArgumentException("student");
    }
}

This of course assumes that Student has a suitable definition of Equals() and GetHashCode(). Depending on the concrete ISet type used you may actually get some nice side effects with a good definition of GetHashCode(), but that discussion is probably a bit out of the scope for this question.

Christoffer
  • 12,712
  • 7
  • 37
  • 53
1

I would use a Dictionary

students Dictionary<int, Student> = new Dictionary<int, Student>();

then check to see if you already have that student

if (!students.ContainsKey(student.id))
{
      students.add(student.id, student);
}
Micah Armantrout
  • 6,781
  • 4
  • 40
  • 66
  • 2
    It's not so much a `Map` as it is a `Set`, so `HashSet` would be more appropriate. – Servy Oct 30 '12 at 18:08
  • ok whats the diff between the two ? HashSet is faster with lots of data but other than that why ? – Micah Armantrout Oct 30 '12 at 18:09
  • Actually, a HashSet really isn't faster, a `Dictionary` is implemented through the same computer science concept of a hash table that `HashSet` is (not to be confused with the C# type `HashTable`, which, is just a non-generic Dictionary. The difference is that a Dictionary (which is a "map") maps a Key in a set of keys to a Value; a Set is just a set of values. You can think of a Map as a Set of KeyValuePairs (which is effectively how it is implemented). The difference is more logical, and conceptual; you don't need a set of IDs and a set of students, you just need a set of students. – Servy Oct 30 '12 at 18:18
  • sounds great so how would you make sure they are unique then ? – Micah Armantrout Oct 30 '12 at 18:20
  • You would override `Equals` and `GetHashCode` for `Student` intelligently, i.e. for `Equals` compare their IDs and for `GetHashCode` just return the hash of the ID. `HashSet` will take care of the rest. If it doesn't make sense to override those methods, or if it's not possible, one can just create a comparer to give to the Set. – Servy Oct 30 '12 at 18:21
  • HashSet is faster with large amounts of data - btw http://stackoverflow.com/questions/150750/hashset-vs-list-performance – Micah Armantrout Oct 30 '12 at 18:23
  • Of course it will be faster than a list, I never said otherwise. I said it wouldn't be noticeably different than a `Dictionary`, as they have approximately the same implementation. – Servy Oct 30 '12 at 18:25
  • 1
    but isn't that kind of logic natively part of a `Dictionary` without overriding anything? – Brad Oct 30 '12 at 18:25
  • 1
    @Brad It's not natively a part of `Dictionary`, it's natively a part of `int`, if you decide to use that as a key. The amount of code would be pretty similar in either case, the point is that a Set would logically represent what is going on, unlike a Dictionary, because logically there isn't a mapping of information, there is simply a single set. – Servy Oct 30 '12 at 18:29
  • Ah it clicked! That does make sense. – Brad Oct 30 '12 at 18:43
  • @Servy I posted your idea as an answer (didn't look like you were going to :) but feel free to edit) http://stackoverflow.com/a/13145889/726127 – Brad Oct 30 '12 at 19:00
  • @Brad I upvoted [this answer](http://stackoverflow.com/a/13145041/1159478) as I feel it contained all of the appropriate information. – Servy Oct 30 '12 at 19:34
1

Use the foreach loop:

    public void AddStudent(Student student)
    {
        if (students == null)
        {
            students.Add(student);
        }
        else
        {
            foreach (var s in students)
            {
                if (student.Id == s.Id)
                {
                    throw new ArgumentException("Error student "
                    + student.Name + " is already in the class");
                }
            }
            students.Add(student);
        }
    }
Gustavo F
  • 2,071
  • 13
  • 23
0

Many ways to do that, here a two possible solutions

1. You can iterate through your list.

bool alreadyInList = false;
foreach (var item in students) 
{
 if (item.Id == student.Id)
 {
    alreadyInList = true;
    break; // break the loop
 }
}

if (!alreadyInList)
{
   students.Add(student);
} 
else
{
     throw new ArgumentException("Error student " 
              + student.Name + " is already in the class");
}

2. Override the Equals method in you Student object and check using Contains.

public class Student 
{
    public override bool Equals(object x) 
    {
        return ((Student)x).Id == this.Id;
    }
}

if (!students.Contains(student)) 
{
   students.Add(student);
} 
else 
{
     throw new ArgumentException("Error student " 
              + student.Name + " is already in the class");
}

More Information:

dknaack
  • 60,192
  • 27
  • 155
  • 202
  • This one worked perfectly, thank you. Thanks everyone else too. – Robert Pallin Oct 30 '12 at 18:24
  • @dknaack This isn't really a good implementation; Lists weren't designed to be efficiently searched the way a set-based data structure would be, such as a HashSet or a Dictionary. Those solutions while they look similar at first glance, end up running substantially more effectively. – Servy Oct 30 '12 at 18:32
0

Make the structure to hold the students be a dictionary<int,Student> and check to see if the ID is already in the dictionary via ContainsKey.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
-1

First read all available id's into a list or array and then make sure that new id's don't match existing id's by checking list or array.

m.qayyum
  • 401
  • 2
  • 15
  • 44