Trouble passing parameters to an object java - java

I'm having trouble passing parameters to specify a specific attributes to an object to change that attribute. I'm a little new to objects and how they work. I need to use objects for this, as it's an assignment.
The purpose of this program is to basically store grades in an electronic gradebook. However, I have an object filled with names and quiz grades of hypothetical students. I need to create the setQuiz() method to grab a specified quiz value of the specified student, and then change it to specified grade. Here's what I have so far.
public class Student extends TestStudent
{
public String name;
public int q1, q2, q3, q4, q5;
public Student(String cName, int cq1, int cq2, int cq3, int cq4, int cq5 )
{
name = cName;
q1 = cq1;
q2 = cq2;
q3 = cq3;
q4 = cq4;
q5 = cq5;
}
public void setQuiz(int grade, int quiz, int student)
{
super.studentAr[student].{quiz?} = grade;
//Basically, I am not sure how to reference the exact grade I need
//to access, thus the question mark.
}
}
So what do I do, StackOverflow? Do I need to totally rethink my structure here? Is it bad practice? Or am I on the right track and just missing something vital?
Thanks a bunch in advance.

With this structure, the only way you can access each quiz is by referring to the quiz specifically. You can't just pass in a quiz number. You must do: student.q1, student.q2 etc.
Another thing that doesn't make sense is that you are passing the index of student into your setQuiz method. This method already belongs to a student object and there is only one object it can affect, which is itself. You need to choose which student to call the setQuiz method on in whatever location that you're calling it from.
EDIT: Changed the constructor to initialize all grades.
A better way to create your class would be as follows:
public class Student extends TestStudent
{
public String m_name;
public int[] m_grades;
public Student(String cName, int q1, int q2, int q3, int q4, int q5)
{
m_grades = new int[5];
m_grades[0] = q1;
m_grades[1] = q2;
m_grades[2] = q3;
m_grades[3] = q4;
m_grades[4] = q5;
}
public void setQuiz(int grade, int quiz, int student)
{
if (quiz > 0 && quiz <= num_quizzes && grade >= 0 && grade < MAX_GRADE) //Always check yout inputs!!
{
super.studentAr[student].m_grades[quiz-1] = grade;
}
}
}
Then you can use it form outside:
Student josh = new Student("Josh", 10, 20, 30, 40, 50);
josh.setQuiz(51, 1);
josh.setQuiz(60, 2);
josh.setQuiz(20, 3);
Or however you'd like to use it.. Up to you!
Another note. When you call super, in this case you are accessing an array on TestStudent class. I have not seen this class and I do not know if it has a studentAr[] member, but it shouldn't!
This array should be in another class that isn't inherited. It oculd be called StudentList or something like that.
EDIT: In response to your comment. If you need the grades to be accessed exactly as you stated, the only solution that comes to mind is:
public void setQuiz(int grade, int quiz, int student)
{
if (quiz == 1)
super.studentAr[student].q1 = grade;
if (quiz == 2)
super.studentAr[student].q2 = grade;
if (quiz == 3)
super.studentAr[student].q3 = grade;
if (quiz == 4)
super.studentAr[student].q4 = grade;
if (quiz == 5)
super.studentAr[student].q5 = grade;
}
Do note, however, that this is a fairly bad way of doing things. When I was handed assignments like this, I usually tried to do them right, impressed the teacher and walked away with an A+. Of course not all teachers appreciate this, so to stay safe you may want to prepare multiple answers - the specific one and the good one.

If you want to access on of a set of things by an index, you want to use an array, so you can use something like q[quiz].

Related

Access elements of arraylist of arraylist of arraylist?

I am new to Java, and I am currently using BlueJ for a project. I am having troubles accessing the objects inside an ArrayList of an ArrayList of such objects. Say I have a Student object:
public class Student
{
private String homeAddress;
private String monthBorn;
private String yearBorn;
private int;
public Student(String homeAddress, String monthBorn, String yearBorn,
int finalGrade)
{
this.homeAddress = homeAddress;
this.monthBorn = monthBorn;
this.yearBorn = yearBorn;
this.finalGrade = finalGrade;
}
}
And then methods to get address, month, year and grade. Then I have a class Class, which is an ArralyList of Student objects:
public class Classroom
{
private String classroom;
private ArrayList<Student> listOfStudents;
public Classroom (String classroom)
{
this.classroom = classroom;
listOfStudents = new ArrayList<Student>();
}
}
And this class includes methods to add Student objects, to list all the students in the class (listAllStudentsInClassroom) which returns an ArrayList of Student, to find the Student with the highest grade in the class (getHighestGradeStudent), and to a list of students with grades higher than a certain amount.
Finally, the class School, which is an ArrayList of Classroom:
public class School
{
private ArrayList<Classroom> school;
public School()
{
school = new ArrayList<Classroom>();
}
}
This includes methods to add a class object, and it should include methods to return the Student with the highest grade ever and a list of students from all classes with grades higher than a certain one. However, I can only get the methods to iterate through only the first class added! Here is the code for getHighestGradeStudentEver so far:
public Student getHighestGradeStudentEver ()
{
Student s = school.get(0).getHighestGradeStudent();
int highestGrade = school.get(0).listAllStudentsInClassroom().get(0).getFinalGrade();
for(int i =1; i< school.size(); i++){
int highestGrade = school.get(i).listAllStudentsInClassroom().get(i).getFinalGrade();
if(value > (highestValue)){
highestValue = value;
s = school.get(i).getHighestGradeStudent();
}
}
return s;
}
This only returns the student with the highest grade from the first classroom object added to School. What am I doing wrong? Sorry for the long question, I tried to be as clear as possible!
If you can already get the highest graded student in a class, you can get that for all the classes, and find the highest grade out of all of those.
// find the highest grade in each class
ArrayList<Student> highestInEachClass = new ArrayList<>();
for (Classroom classroom : school) {
highestInEachClass.add(classroom.getHighestGradeStudent());
}
// find the highest grade overall
Student highestGradeStudent = highestInEachClass.get(0);
for (Student student : highestInEachClass) {
if (highestGradeStudent.getFinalGrade() < student.getFinalGrade()) {
highestGradeStudent = student;
}
}
return highestGradeStudent;
Alternatively, use Stream:
return school.stream().flatMap(x -> x.getListOfStudents().stream())
.sorted(Comparator.comparing(Student::getFinalGrade).reversed())
.findFirst().orElse(null);
As I understand your question, you already have a function Classroom.getHighestGradeStudent() which gives you the best student of that class. You also have a way to get the grade of a given student, since the Student object contains .finalGrade.
You want to loop through all classrooms in the school, and find the student with the highest grade.
So you have your for loop, which iterates over the classrooms. And for every classroom, you get some arbitrary student's final grade:
int highestGrade = school.get(i).listAllStudentsInClassroom().get(i).getFinalGrade();
^
This is likely not what you want. Instead, you want the best student's grade from that classroom. For that, you should instead use
int highestGrade = school.get(i).getHighestGradeStudent().getFinalGrade();
(If my assumption is wrong and you do not have a function getHighestGradeStudent() of a given classroom, you would need to loop over the result of listAllStudentsInClassroom() (or store that list sorted))
Then, you can continue with your code as you're doing, by updating the stored best student s if the best student of the current classroom is better than what you previously had in s.
But make sure you use either highestGrade or highestValue, not both of them. As your code stands, I don't see highestValue defined anywhere.
Note, that it's possible to make this code more efficient, if you only search for the best student in a given class once. I would do
Student bestOfClassroom = school.get(i).getHighestGradeStudent();
int highestGrade = bestOfClassroom.getFinalGrade();
so you already have your student to store in s by simply doing s = bestOfClassroom instead of searching through the whole list again.
But this is an optimization that should not be relevant for the Correctness of your program.

Library System: Borrowing

I do not know how to do the borrowHolding() in the Library Menu I have to create.
So the purpose of the borrowHolding() is for members to be able to borrow books or videos.
This is a just a sample data of the array:
member[0] = new StandardMember("ID", "Name");
member[1] = new PremiumMember("ID", "Name");
holding[0] = new Book("ID", "Title");
holding[1] = new Video("ID", "Title", loanFee);
This is the borrowHolding() method in the TestLibrary class: (the array is in the TestLibrary class too)
public static void borrowHolding(){
String option;
option = input.next();
do{
Scanner scan = new Scanner(System.in);
int tempId = 0;
System.out.println("Enter your ID: ");
String searchID = scan.next();
for(int i = 0; i < member.length; i++){
if(member[i].getID().equals(searchID)){
tempId = i;
}
}
So for the method, I tried to write a code that will search through the array to find the memberID that wants to borrow. It is not completed yet because I believe I am not doing it correctly
There is a Member class that contains
public class Member{
public Holding[] getCurrentHoldings(){
}
}
from the name of the method, it is used to store the holdings of the members that borrowed. So if member 1 borrows a book, that book will be stored inside the array, i think. I was thinking of using an ArrayList for this method, but not sure if it would make sense.
To borrow a book or video, there are certain conditions to be able to borrow, but I do not know how to implement this into the borrowHolding(). One of the condition are in the Holding class.
public class Holding{
public boolean borrowHolding(){
if(status == true && isOnLoan() == false)
borrowDate = newDateTime(); //this is to get the time when the book or video is borrowed
return true;
}else
return false;
}
}
And there is another condition in the Member class is that the Member must have enough credit to borrow. A book loan fee will cost $10 and a video will vary from $4 or $6.
I think I wrote a few information that is not needed but I guess its better than less information.
My problem is what do I do to the borrowHolding() method in the LibraryMenu? how do I make that if a member wants to borrow a holding, the holding will go under the member's array in the member class
public class Member{
public Holding[] getCurrentHoldings(){
}
}
with the condition from the holding class if it is met, and while executing the borrowHolding method, the method from the member class will be able to subtract the member credit by the loan fee from the book or video. is it possible?
public class Member{
private int credit = 30;
public int calculateRemainingCredit(){
credit = credit - //(the loan fee from the book or video class)
}
}
If your intentions are to add a holding to the member class then this is possible. I would suggest adding an ArrayList of Holding's rather than a regular array because it seems as if the size is going to be constantly changing.
public class Member{
private ArrayList<Holding> currentholdings; // you may need to import the arraylist
private int credit;
public void init(){ // goes in constructor
currentholdings = new ArrayList<Holding>();
credit=0;
}
public void addHolding(Holding newholding){ // adds a new holding to the members array
currentholdings.add(newholding);
credit-=newholding.getFee(); // will need to add a fee variable to the holding class;
}
}
And as for checking to see whether or not the member has enough "credit", that can be done in the borrowHolding() method right after you identify the index of the array. I would just recommend adding a parameter of the member to the borrowHolding() method so you can easily access the variables from that member.
if(member[i].getID().equals(searchID)){
tempId = i;
int tempHolding; // index of whatever holding you wanted (could get this from the scanner)
if (holding[tempHolding].borrowHolding(member[tempId])){ // check status
member[tempId].addHolding(holding[tempHolding]); // they have passed the req. so you can add the holding
}
break;
}
Hope this answered your question.

java: confusing instructions, shopping cart program

My teacher gave me confusing instructions on this coding assignment. If you guys could help elaborate or give me tips, I'll provide what I have.
First of all the program is where I have to make 2 classes that will work with a big class to produce a shopping list where you can edit how much of each item you want. Have to take the name of an item, how many times its purchased, and how much each one costs.
I finished my first class, I'll post the entire coding and rules for the coding at the bottom of this question.
Okay so here's what I have. I'll go step by step.
Rule 1: A field private Purchase[] as an array of purchases.
Another int field that tracks how many purchases have actually been made
So I made this:
private int Purchase[];
private int purchaseCount;
Rule 2: Negative values do not make sense, so just reset those to zero if provided by user
Okay so in the first program I had to do the same thing, but I'm confused how to do it now.
I implemented the "reset to zero" in the modifiers, but now my teacher is not asking for modifiers. Am I supposed to put them anyway? I know I just have to put an "if blahblahblah < 0, then blahblahblah = 0" thing, but how do I go about that?
Rule 3: Accessor .length() method that returns your int field for how many purchases
public int Purchase(){
return ;
}
I guess this is about all I know for that. I know I have to return something, not sure how to use length though. And I think there's a parameter.
Final Rule 4: Accessor .get(int) for the Purchase array, which needs a parameter that will index the array. So get(0) returns the first element (a Purchase object) of the array.
I think I understand this, but since I don't know how to do the last step, I haven't tried this yet. ".get(int)" what? So an accessor where I perform a .get(int) inside it? I don't know much about accessors, this is why I need this help. The rest of the program seems pretty simple for me, but this initial stuff confuses me. Thanks.
Rules for already completed class:
Three fields, a String for name of the purchase, int for units purchased, and a double for cost per unit.
• Standard accessors and modifier methods for each field.
• Negative values are not allowed, so change those to zero in all cases.
• Constructor to initialize these three fields (String, int, double) in that order.
• Constructor overload, (String, double) assumes the int quantity is zero.
• Default constructor that assumes name is “” and numbers are zero, must call the three argument constructor.
• A getCost method that is simply the number of units purchased times unit price.
• A toString method return a String with the item name followed by the unit price in parentheses
Completed program:
public class Purchase {
private String purchase;
private int unitsPurchased;
private double costPerUnit;
// Accessors
public String purchase() {
return purchase;
}
public int unitsPurchased() {
return unitsPurchased;
}
public double costPerUnit() {
return costPerUnit;
}
// Modifiers
public void setPurchase(String purchase) {
this.purchase = purchase;
}
public void setunitsPurchased(int unitsPurchased) {
if (unitsPurchased < 0) {
unitsPurchased = 0;
}
this.unitsPurchased = unitsPurchased;
}
public void setCostPerUnit(double costPerUnit) {
if (costPerUnit < 0) {
costPerUnit = 0;
}
this.costPerUnit = costPerUnit;
}
//constructors
public Purchase() {
this("", 0, 0);
}
public Purchase(String initialPurchase, double initialCostPerUnit) {
this.purchase = initialPurchase;
this.unitsPurchased = 0;
this.costPerUnit = initialCostPerUnit;
}
public Purchase(String initialPurchase, int initialUnitsPurchased, double initialCostPerUnit) {
this.purchase = initialPurchase;
this.unitsPurchased = initialUnitsPurchased;
this.costPerUnit = initialCostPerUnit;
}
//end of everything I am sure about
//beginning of unsurety
public static double getCost(String purchase, int unitsPurchased, double costPerUnit) {
return unitsPurchased * costPerUnit;
}
public static String toString(String purchase, int unitsPurchased, double costPerUnit){
return purchase + costPerUnit;
}
}
Okay, so first rule 1 the code should look like:
private Purchase[] purchases;
private int purchaseCount;
Remember, in this case since you've already defined Purchase in your other java file, you're using it as a datatype, not as an identifier.
For rule 2, you're going to want that if statement in the access methods for purchaseCount as well as in the constructor.
Rule 3 is extremely vague...but my best guess is your teacher wants you to define a length method for that class, so that when you call say purchases.length() it returns the purchase count.
Again, rule 4 is vague, but my best guess is you need to define a get method for that class that just returns a value from your private purchases array using a given index.
Something like this:
public Purchase get(int index) {
return purchases[index]
}
I hope this helps and good luck!!

How to expand a randomHuman constructor to take two types of objects?

I am a java-noob as I recently started to learn in a course.
I have created a class:Humans which have ability to store their name and age, and also a subclass Students which extends Humans and adds the Year they began there studies.
I have constructed a randomHuman constructor where I call it(in my main class) and create a list with the humans(with random name and age).
My problem is when i want to random 5 human non-students and 5 students and create this list, I'm not sure how to find out what type of object is sent to the random constructor, so i know if i should give it a year or not. And what type to tell the constructor to return.
I am sorry that this turned into an essay, but if anyone would be so kind to help then I would greatly appreciate it.
TLDR; How to expand a randomHuman constructor to take two types of objects?
Here is my main class:
public class Main {
public static void main(String []args){
Human newHuman = new Human( 18, "Tommy");
System.out.println("Age: " + newHuman.getAge());
System.out.println("Name: " + newHuman.getName());
System.out.println(newHuman.toString());
Human putte = new Human (25,"Putte");
System.out.println(putte);
//Varför blir det så?
//kanske lokal variabel
//Array RandomHumans
System.out.println(" ");
System.out.println("Array Human");
ArrayList<Human> myAl = new ArrayList();
for(int i = 0; i<15; i++){
Human xx =Human.randomHuman();
myAl.add(xx);
}
//Array RandomFysiker
for(int j = 0; j<myAl.size(); j++){
Human var = myAl.get(j);
System.out.println(var.toString());
}
System.out.println(" ");
System.out.println("Array Fysiker");
ArrayList<Fysiker> myAl2 = new ArrayList();
//puts the Fysiker in an array
for(int i = 0; i<15; i++){
Fysiker xx =Fysiker.randomHuman();
myAl2.add(xx);
}
//prints teh array
for(int j = 0; j<myAl2.size(); j++){
Fysiker var = myAl2.get(j);
System.out.println(var.toString());
}
}
}
and my Human class:
public class Human {
public String name;
public int age;
Human(int ageIn, String nameIn){ //Constructor
age=ageIn;
name=nameIn;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String toString(){
return "Name: " + getName() +"," + " Age: " + getAge();
}
//Random human
// Behöver ändra konstruktorn så att den kan kolla
// om objectet är Fysiker eller Human och sedan,
// Behandla dom olika
//Problem1: Hur kollar man? Föreslag if(obj instanceof Fysiker), men vad ska jag ha som obj
//Problem2: Vilken returtyp ska man då ha?
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// if(xx instanceof Fysiker){
//
// }
return new Human(randomAge,randomName);
}
}
and the subclass Fysiker(aka student):
/**
*
* #author Julian
*/
public class Fysiker extends Human{
public int schoolYear;
public Fysiker(int startYear,int ageIn, String nameIn){
super(ageIn, nameIn);
if (age>15){
if (startYear>2013){
} else if (startYear<1932){
} else {
schoolYear = startYear;
}
} else {
}
}
public int getYear(){
return schoolYear;
}
public String toString(){
return super.toString() +","+" Startyear: " +getYear();
}
}
Actually, your randomHuman() method, as mentioned in the comments, is not a constructor at all. It's a static factory method, although I'm sure you're not aware of what that means as yet.
Basically, a constructor is not a method at all and doesn't have a return type. What a constructor does is provide an initialization for a new instance of the class, created by using new, although it can do things that don't strictly initiate the fields of that object.
A method, in contrast, can return something. And in your particular case, the last line actually tells you exactly what it returns - it's calling new for the class Human, so it will return an object of class Human, never a Student.
In fact, the class Human is not aware of the class Student. In principle, you could write a subclass for a class, years after the parent class has been written. Parent classes don't need to know about their descendents. They just decide what they allow those descendents to change and what they don't allow them to change.
You could, in theory, put a method in Human that creates a Student instance. But I'm pretty sure that's not needed in the current situation.
What you probably want to do is fill a list of humans outside the definition of either Human or Student. Filling a random list is probably not part of "being a human" or "being a student" is all about, so you should just do it in your Main class, calling new Human() or new Student() as you wish and filling them as appropriate. Since you know which new you called, you also know whether or not to use a random year.
You could do it in a static method in your Main class, to signify that this is something you do for testing, and not really part of the logic of either a Human or a Student.
As for being able to tell which object you now got from the list - you can do that with instanceof. But you'll also need to typecast it to Student if you want to access its getYear() method.
However - and this is the neat thing about polymorphism - if you just call the toString() method, and don't even check the type of the object, you'll get it with the year if it's really a Student object, and without it if it's a plain Human object.
Let's assume your teachers actually want you to extend the randomHuman method so that it sometimes gives Human instances, and sometimes Students. When it gives Student, it should of course provide it with a year.
As I said above, this is called Tight Coupling between parent and subclass, and is not recommended. If I wanted to build another human subclass, such as Politician, I'd have to call you and ask you to release a new version of Human that also sometimes gives random Politicians. So, under protest, I'll explain how to do it.
Your existing function is:
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// if(xx instanceof Fysiker){
//
// }
return new Human(randomAge,randomName);
}
We change it like so:
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
Human result = null;
if ( Math.random() < 0.5 ) {
// With a probability of 50%, create a plain human
result = new Human( randomAge, randomName );
} else {
// Create a student. Start by calculating a random year.
int randomYear = (int) (Math.random()*(2013-1932) + 1932);
result = new Fysiker( randomYear, randomAge, randomName );
}
return result;
}
So, you decide that you want to make a plain human, and within the scope of that decision, you create it with new Human(...) and assign to the result variable.
If you decide to make a student, within the scope of that decision, you calculate a random year, and create it with new Fysiker(). You can assign it to the variable result because polymorphically, it's Human. But in reality, internally, it's a Student.
You return the result variable, which may contain either a Human or a Student at this point.
For determining what type the object instance is use either object instanceof class or object.getClass().equals(Clazz.getSimpleName())
For return type just use the superClass (or interface). You can always cast it to the child if needed.
If you want to create 5 class of each you need a boolean in the method declaration and call it 5 times each to be sure u will have 5 instances of each class.
public static Human randomHuman(boolean isHuman){
If this is not important u can add a random boolean and then call the constructor:
boolean isHuman = Math.random() < 0.5;
if(!isHuman){
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// create student
} else {
// create human
}

comparing objects

I have two student objects.
class Student{
int physics;
int english;
int chemistry;
}
I need to compare Student A marks in each subject with Student B's marks in all the subjects.
A marks in physics needs to be compared with B's marks in physics, english, chemistry.
Similarly A's english with all the three of B.
if there is atleast one match say A's chemistry marks are equal to B's english marks,
then stop execution and return false.
My logic is
if(a.getPhysics==b.getPhysics || a.getPhysics==b.getEnglish || a.phy==b.chem || ...){
return false;
}
Is this better or any other good logic ??????
Well, you will have to make O(n^2) comparisons in any case, the question is how clean the code will be.
What you are suggesting now is good for 6 boolean comparisons, what if you have 30 subjects? Will you maintain the hundredss of comparisons you need to make?
Keeping it simple, I would prefer keeping the grades in a List or a Map and then do a nested iteration:
for (int gradeA : thisStudent.getGrades()) {
for (int gradeB : otherStudent.getGrades()) {
if (gradeA == gradeB) return false;
}
}
return true;
Of course this code needs to be adapted to your scenario (different iteration on List vs. Map, optimization by not checking each grade every time, extracting a method out of this, etc...)
A little improvment would be to create a method in the Student class to do it.
Those attributes (the courses physics, english, ...) shouldn't be in the Student class. A better option would be to create a CourseModel where your store all your Courses and keep track of all the Students who are enrolled in a course. From your CourseModel, you can query for a particular Student and get all their courses back (as a array/collection). When you have two collections/arrays, simply create a nested for-statement to compare all of them.
Use HashSets:
Set<Integer> aMarks = new HashSet<Integer>();
Set<Integer> bMarks = new HashSet<Integer>();
Collections.addAll(aMarks, 2, 3, 9);
Collections.addAll(bMarks, 4, 2, 2);
boolean check = Collections.disjoint(aMarks, bMarks);
return check;
The values are just for test. You can change Collections.addAll(...) with a new method Student.getMarksAsSet()
You could add the ability for Student to return its marks as a set:
public class Student {
private int physics;
private int english;
private int chemistry;
public Student(int physics, int english, int chemistry) {
this.physics = physics;
this.english = english;
this.chemistry = chemistry;
}
public Set<Integer> marks() {
return new HashSet<Integer>(Arrays.asList(physics, english, chemistry));
}
}
Then, when are trying to determine if two students match, all you need to see is whether their two respective sets of marks are disjoint, as StudentMatcher does:
public class StudentMatcher {
public boolean matches(Student student1, Student student2) {
Set<Integer> studentMarks1 = student1.marks();
Set<Integer> studentMarks2 = student2.marks();
return haveIntersection(studentMarks1, studentMarks2);
}
private boolean haveIntersection(Set<Integer> studentMarks1, Set<Integer> studentMarks2) {
return studentMarks1.removeAll(studentMarks2);
}
}
And here is a unit test to verify it works:
public class StudentMatcherTest {
#Test
public void matches() {
StudentMatcher matcher = new StudentMatcher();
Student student1 = new Student(34, 45, 66);
Student student2 = new Student(99, 55, 34);
Student student3 = new Student(11, 22, 33);
assertTrue("Should match", matcher.matches(student1, student2));
assertFalse("Should not match", matcher.matches(student1, student3));
}
}
There is more that can be done to make this better, but I'm assuming your code is more complicated than what you've posted, so hopefully this is enough to get you on a better path.
If the marks are in a small range (A-F rather than percent), and you need to compare marks in many subjects rather than the three you give, populate an array of boolean values to hold whether the first student has the given mark, then for the second check whether the array has a value set. That would be O(N+M) where N is the number of subjects and M the number of possible grades.
If you only have the three subjects, having the tests hard coded isn't that bad - you'll need six lines to get the marks from each anyway.

Categories