Reputation: 173
In case 5 of the switch statement below I'd like the user to input one of the students from the array and select a module from the modules array to enrol them on without duplication. Any ideas/examples would be very useful. Thanks in advance.
Control Class:
import java.util.Scanner;
public class Control {
public void run() {
while (true) {
Menu menu = new Menu();
menu.getMainMenu();
try {
Scanner scan = new Scanner(System.in);
int selection = scan.nextInt();
switch (selection) {
case 1:
for (Student student : students) {
System.out.print(student.getName() + " ");
}
break;
case 2:
for (Module module : modules) {
System.out.print(module.getName() + " ");
}
break;
case 3:
...
case 4:
...
case 5:
// Print out students
System.out.println("select a student: ");
for (int i = 0; i < students.length; i++) {
System.out.println(i + " " + students[i]);
}
selection = scan.nextInt();
############################
Confusion here
############################
case 6:
System.out.println("Goodbye!");
System.exit(0);
break;
default:
System.out.println("Invalid option selected. You must enter a number between 1 & 6!");
} // end switch
} catch (Exception e) {
System.out.println("Invalid entry. You must enter a number between 1 & 6");
}
} // end while
}
}
Upvotes: 1
Views: 483
Reputation: 16209
There is a conceptual weakness in your class model which is giving you troubles. Because a Student has a list of Modules and a Module also has a list of Students you have to do bookkeeping in two places and there is a potential for inconsistency, for example:
jane : UFCE1, UFCE2
UFCE1 : alex, mike
An object model like this is guaranteed to give you (or the developer who has to maintain your code after you have left) terrible headaches.
What you could do is remove the lists from the Student and Module classes and create a service class which keeps track of enrollments:
public class EnrollmentService {
private final Map<Module, List<Student>> enrollments;
public boolean addModule(Module module) {...
public boolean enroll(Student student, Module module) {...
public final List<Student> getStudents(Module module) {...
public List<Module > getModules(Student student) {...
}
(See complete code example)
Each design decision is a tradeoff. Here the obvious drawback is the 'getModules' method, which has to walk the map to collect all modules a given student has enrolled in. You could opt for a second map to keep track of this reverse lookup which is faster, but gives you a double bookkeeping again. Having a double bookkeeping in a single class is a bit less of a pain than having it in separate classes though...
Another often used and perfectly valid way to model this, is to keep track of the Student-Module relation in only one of the domain classes. In this case I would choose Module but it really depends on your requirements. Of course you still need a service class to enroll Students and perform lookups.
A few remarks in closing:
I hope this helps!
Upvotes: 1
Reputation: 20323
Your criteria for equality is name for Student add equals and hashcode implementation to it like :
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student)) {
return false;
}
Student other = (Student) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
Now in your Module
class addStudent() method you have following choices of implementation :
if(!students.contains(student) {
students.add(student);
} // You will add to the list only if Student with same name doesn't exist.
OR change to Set implementation so from List students it will become Set
and then in your addStudent
method your call will be
students.add(student);//this call will check if there is any student object already in the set with same name, if yes it wont add or else student will be added
Upvotes: 0
Reputation: 12339
In your example, the identifier and test-for-uniqueness for the student is the name (jane/alex/mike).
If you used a HashMap with the name as the index, then adding (with .put) to the HashMap will add if new but not duplicate if repeated.
You might want to consider overriding equals() and hashCode() to tell Java how to determine whether two students are the same. The name alone will give you problems if you have two different students with the same name.
Upvotes: 1
Reputation: 15729
While I agree with the sentiments to use Sets, sometimes a List feels better or more natural because it has the notion of ordering. You can, for example, sort by GPA and ask for the 3rd best student.
you could do something like
synchronized boolean addFoo(Foo foo) {
if mList.contains(foo)
return false;
else
return mList.add(foo);
}
Upvotes: 0
Reputation: 4093
You can use set implementation (HashSet, LinkedHashSet) to avoid duplicates.
or use ArrayList. But in this case do the check
list.contains(obj)
before insertion
With HashSet you will not know the order of insertion. but with LinkedHashSet and ArrayList you can
and if needed you can use
toArray()
function in Set or ArrayList to convert the list to array
Upvotes: 1
Reputation: 459
I would use a Set instead of an array if possible. Then you can just implement .equals and .hashcode in your Student class and have control over what 'duplication' means in your application.
If order is important too, perhaps a LinkedHashSet...
Upvotes: 0
Reputation: 14675
If you want to avoid duplicates, don't use arrays or Lists. Use a Set.
Upvotes: 1