What is wrong with my comparable interface logic? - java

So the question is as follows
A unique id is assigned to each student entering the queue. The queue serves the students based on the following criteria (priority criteria):
The student having the highest Cumulative Grade Point Average (CGPA) is served first.
Any students having the same CGPA will be served by name in ascending case-sensitive alphabetical order.
Any students having the same CGPA and name will be served in ascending order of the id
My code
class Priorities{
public List<Students> getStudents(List<String> events) {
PriorityQueue<Students> pq = new PriorityQueue<Students>();
for ( String s : events) {
if ( s.contains("ENTER")) {
String [] arr = s.split(" ");
int id = Integer.parseInt(arr[3]);
String name = arr[1];
Double cgpa = Double.parseDouble(arr[2]);
pq.add(new Students(id, name, cgpa));
}
else
pq.poll();
}
List<Students> studentList = new ArrayList<Students>(pq);
return studentList;
}
}
class Students implements Comparable<Students>{
int id;
String name;
double cgpa;
public Students(int id, String name, double cgpa) {
this.id = id;
this.name = name;
this.cgpa = cgpa;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getCgpa() {
return cgpa;
}
public void setCgpa(double cgpa) {
this.cgpa = cgpa;
}
// -1 return left, 1 return right
public int compareTo(Students other) {
if ( this.equals(other))
return 0;
else if ( this.getCgpa() > other.getCgpa())
return -1;
else if ( this.getCgpa() < other.getCgpa())
return 1;
else if ( this.getCgpa() == other.getCgpa() && this.getName().compareTo(other.getName()) == 0)
return Integer.compare(this.getId(), other.getId());
else
return this.getName().compareTo(other.getName());
}
}
Sample input
12
ENTER John 3.75 50
ENTER Mark 3.8 24
ENTER Shafaet 3.7 35
SERVED
SERVED
ENTER Samiha 3.85 36
SERVED
ENTER Ashley 3.9 42
ENTER Maria 3.6 46
ENTER Anik 3.95 49
ENTER Dan 3.95 50
SERVED
Sample output
Dan
Ashley
Shafaet
Maria
I'm getting the following
Dan
Ashley
Maria
Shafaet
Edit: Using
List<Students> studentList = new ArrayList<Students>();
while(!pq.isEmpty())
{
studentList.add(pq.poll());
}
instead of List studentList = new ArrayList(pq); helps with copying the exact order of the PQ to the list.

The general structure of a comparator should be: compare a field; if the field values differ, return; if they are the same, proceed to the next field.
In this case, it could look something like:
int cmp;
cmp = Double.compare(other.getCgpa(), this.getCgpa());
if (cmp != 0) return cmp;
cmp = this.getName().compareTo(other.getName());
if (cmp != 0) return cmp;
cmp = Integer.compare(this.getId(), other.getId());
if (cmp != 0) return cmp;
return 0;
(The last if and return could be collapsed to just return cmp;; but I think it's easier to extend later if you do it as above, because you can then just insert another cmp/if.)

The issue is that PriorityQueue's ordering semantic are not guaranteed in its iterator (on top of that, note that PriorityQueue is not a List !)
Quoting from the java doc (emphasis mine) :
This class and its iterator implement all of the
optional methods of the Collection and
Iterator interfaces. The Iterator provided in method
iterator() is not guaranteed to traverse the elements of
the priority queue in any particular order. If you need ordered
traversal, consider using Arrays.sort(pq.toArray()).
Which means you will not get your comparator's ordering unless you use the queue semantics (e.g. add, poll, remove, offer... and the likes).
And looking at implementations, calling new ArrayList<Students>(pq); (or PriorityQueue#toString() for that matter) is implemented using an iterator, so it does not respect the priority.
The takeaway here :
Using PriorityQueue is OK in the case of queue semantics only, not iteration / random access
Combining both List and "live" sorting is not provided by a standard Java class that I know of (see also). (You can sort a list using a comparator, but there is no list that is sorted each time you add an element). There are such collections, though, using Set semantics, see TreeSet, you'll find them on the linked answers. Be warned that Set semantics are different (they maintain unicity of their elements, the meaning of unicity being somewhat tricky to get. For example, HashSet unicity is defined by hashCode/equals, but TreeSet's is defined by a comparator's).
That being said, Andy's implementation of the comparator is by far more readable (and avoids repetitions).

Related

Java-Selection sorting an array of objects by an int key and displaying in table

I am currently working on a project for school and am really struggling. I am supposed to selection sort a group of Student objects and then display them in selection sort order.
Create an array with the size of 10 and assign student details (Name, BroncoId, age and TotalMarks) to the array. Perform the selection sort to sort the students in descending order based on their total marks.
a. Steps:
i. Create the student list (use Random class in java to generate the age (15-25) and total (0-100))
ii. Print the Student List in a table format
iii. Perform selection sort based on the total marks of the students
The place I am stuck at currently is making the selection sort. I understand how to create the selection sort, but I can't seem to translate it for this implementation.
My selection sort code:
public static Student[] selectionSort(Student[] studentList)
{
for(int i = 0; i <studentList.length-1; i++)
{
int minIndex = studentList[i].getGrades();
int pos = i;
for(int j = i + 1; j < studentList.length-2; j++)
{
if(studentList[j].getGrades() > studentList[minIndex].getGrades())
{
minIndex = studentList[j].getGrades();
pos = j;
}
}
int temp = studentList[pos].getGrades();
studentList[pos] = studentList[i];
int k = studentList[i].getGrades();
k = temp;
}
return studentList;
}
When I run this code, the console returns:
I sought tutoring to hopefully fix this problem, but my tutor gave me a few nonfunctional suggestions. We were both stumped at the end of the session.
My code for printing:
public static void printStudentInfo(Student[] students)
{
System.out.println("Name: AGE: idNumber: Score:");
for(Student student: students)
{
if(student.getName().length() <= 49)
System.out.printf("%-50s %-5d %-10s %-4d\n", student.getName(), student.getAge(), student.getID(), student.getGrades() );
else
{
System.out.printf("%-50s %-5d %-10s %-4d\n", student.getName().substring(0,48), student.getAge(), student.getID(), student.getGrades() );
System.out.println();
int i = 0;
while(i <= student.getName().length())
{
System.out.printf("%-50s", student.getName().substring(49 +48*i, 97+48*i) );
System.out.println();
i++;
}
}
}
}
As more of an issue out of passion, I sought to make an interesting print method. My problem is, also that I don't really know how to parse and format a string of 155 characters for instance. What do I put in this while lop to accomplish this?
I want the program to output one object name line like:
49 characters
49 chars
…
What ever is left
It probably won't ever go past three lines, but hey, who says I can't give an example like that? What do I put in the header of the while loop to accomplish this?
PS:
Here is the Student class if you need it.
public class Student
{
private String name;
private int age;
private String idNumber;
private int gradePoints;
public Student(String name, int age, String idNumber, int gradePoints)
{
this.name = name;
this.age = age;
this.idNumber = idNumber;
this.gradePoints = gradePoints;
}
public void setName(String name)
{
this.name = name;
}
public void setAge(int age)
{
this.age = age;
}
public void setidNumber(String idNumber)
{
this.idNumber = idNumber;
}
public void setPoints(int gradePoints)
{
this.gradePoints = gradePoints;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String getID()
{
return idNumber;
}
public int getGrades()
{
return gradePoints;
}
Welcome to SO Matthew.
Rather than giving you a solution I thought it might be useful to give you a process for solving the problem yourself.
Good practice in software development is to break your problem down into very small components, make sure each of those work perfectly (through unit testing) and then build your solution from those components.
In line with that practice I suggest you do the following:
list each of the individual steps required to do a selection sort on paper.
Pick the simplest one (e.g. swapping two elements).
Write a unit test that would pass if your swap method worked
run the unit test and verify that it fails
write the simplest code you can to make that test pass
write a new test to cover a more complex scenario that isn't yet supported
keep going until you believe that method works perfectly
move onto the next method
once all the components are working perfectly write the method that calls them all using the same process (i.e. test first then code)
If you follow this process then you will end up with a system that you understand perfectly, works, is maintainable, and that you can refactor. It has another very significant benefit: it means when you come to SO with a question you'll be asking about a specific item that you don't know how to solve rather than a 'why doesn't my code work' question. Specific questions tend to get better and faster responses.
In your case, I would start with methods for swapping items (hint: your code for this doesn't work which you'll discover quickly when you write a unit test) and then move on to finding the smallest item in a sublist. Then a method that uses those two to put the smallest item at the start of a sublist. Finally a method that performs that method for all sublist progressively. Make sure each method is working perfectly, including checking validity of arguments, before you move on to putting them together.

Bubble sort Arraylist of objects

The aim of this method here is to bubble sort according to a person's ID
however in this area:
if (al.get(i).compareTo(al.get(i+1)) > 0 )
it states: cannot find symbol - method compareTo(java.lang.Object)
This is the class person (not very imp) / / / /
public class Person implements java.io.Serializable
{
String personID;
String name;
byte dayDOB;
byte monthDOB;
short yearDOB;
String telNum;
}
This is the sort method:
public static void sort(ArrayList al)
{
Person p;
String temp;
boolean flag = true;
System.out.println("Database will be sorted acc to ID ");
System.out.println();
while (flag = true)
{
flag = false;
for (int i=0;i<al.size()-1;i++)
{
p = (Person) al.get(i);
if (al.get(i).compareTo(al.get(i+1)) > 0 )
{
temp = al.get(i);
al.set(i,al.get(i+1) );
al.set(i+1, temp);
flag = true;
}
}
}
}
PS; I am a newbie when it comes to code and have been modifying this code for up to 7 hours already
Objects come with a built in compareTo() method, but it's best to override the default. See the java documentation for compareTo(). That should simplify your code quite a bit.
Your Person class will need to implement Comparable and include that in the class declaration. You can then write a compareTo() method something like this:
public int compareTo(Person b) {
return this.name.compareTo(b.getName());
}
A compareTo() method should return -1, 0, or 1. If you call a.compareTo(b) in your main class, compareTo() should return zero if the objects are sorted to the same place (i.e. equal), -1 if object a should be sorted before object b, or 1 if object a should be sorted after b.
You'll need to decide what constitutes the same person and how they should be sorted. Alphabetically based on name? Name and id? Whatever it is for your program.

LinkedHashMap searching

I have a class
class polygon
{
private String name;
private int quantity;
// default constructor
private polygon()
{ }
public String get name() {
return name;
}
public void setname(String name) {
this.name = name;
}
public int getquantity() {
return quantity;
}
public void setquantity(int quantity) {
this.quantity = quantity;
}
}
and also I have a map like this:
LinkedHashMap<Integer, polygon> polymap = new LinkedHashMap<Integer, polygon>();
I have to ask two questions:
How can I find if there is a member with specific value which has the name like "square"?
How can I get all the member with the lowest quantity?
Thanks.
What we have learned from comments and updates: Polygon is a class with members String name (possibly but not necessarily unique) and int quantity (no restriction). There is also a timestamp, and this Integer is used as a key in the
Map<Integer,Polygon> polymap
To find all Polygons with a given name:
for( Polygon polygon: polymap.values() ){
if( polygon.getName().equals( givenName ) ){ //... }
}
Now this is a sequential search and may take some time if the number of entries is very big. Assuming names are unique, O(1) access time can be achieved by creating another Map in parallel to polymap, mapping name strings to Polygon objects. (Consider the additional effort for removing, but Map.remove( ., . ) should help.)
To find all Polygons with the minimum quantity, determine the minimum while keeping a set of the Polygons with that minimum:
int min = Integer.MAX_VALUE;
Set<Polygon> polyset = new HashSet<>();
for( Polygon polygon: polymap.values() ){
int qtty = polygon.getQuantity();
if( qtty < min ){
min = qtty;
polyset.clear();
polyset.add( polygon );
} else if( qtty == min ){
polyset.add( polygon );
}
}
Again, a sequential search, but here a second map will require a multimap, i.e., a Map<Integer,Collection<Polygon>>.
LinkedHashMap<Integer, polygon> polymap = new LinkedHashMap<Integer, polygon>();
How can I find if there is a member with specific value which has the name like "square"?
The containsValue() uses equals method for find the match. You can override the equals() method of the polygon class. Then you can use the containsValue(new polygon()) to find whether the value exist or not. The equals method implementation will be completely depended on the name field of the polygon class. Something like this:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof polygon)) return false;
polygon polygon = (polygon) o;
if (!name.equals(polygon.name)) return false;
return true;
}
Note: You are overriding the equals() method of the class, so could have some side affects on how you are using it at other places in your application.
How can I get all the member with the lowest quantity?
I would suggest you maintain a separate PriorityQueue for finding lowest quantity polygon. Provide a custom Comparator while initializing the queue.

Find Range in which value lies in Java

Suppose, I have an unsorted array of ranges.
For e.g
class CreditRange{
long credits;
int id;
}
Now I want to find, given credit count value belongs to which one of the CreditRange.
Possible Set<CreditRange> of values can be
CreditRange :{id:1,credits:0}
CreditRange :{id:2,credits:100}
CreditRange :{id:3,credits:500}
CreditRange :{id:4,credits:250}
Case 1 : Now when user enters Credits = 50, this range comparator should give
answer as
CreditRange :{id:1,credits:0}
Case 2 : Now when user enters Credits = 300, this range comparator should give
answer as
CreditRange :{id:4,credits:250}
Case 3 : Now when user enters Credits = 600, this range comparator should give
answer as
CreditRange :{id:3,credits:500}
We can assume the ranges array takes ~1M and fits the memory. I am looking for an easy algorithm, which uses only standard JDK collections without any 3d-party libraries and special data structures, but works reasonably fast.
What would you suggest?
I guess, it's not the range you are talking about. Rather you want the largest element that is less than your passed element.
You can follow the below steps to solve the problem:
First implement a Comparator for your class, which compares on the basis of credits
Then, use a TreeSet, passing an instance of that comparator to it's constructor. It will sort the item inside it, as per the comparator.
Then use TreeSet#floor(E) method to get the greatest element which is less than E, as per the comparator. Of course, you have to create an object of CreditRange to search. You can't just search for 300.
Demo code:
NavigableSet<Integer> set = new TreeSet<>();
set.add(0); set.add(100);
set.add(250); set.add(500);
System.out.println(set.floor(50)); // 0
System.out.println(set.floor(300)); // 250
And please rename your class. It is not depicting the range in any manner. It should perhaps be better named as CreditBound as specified by Jon Skeet in comments.
As mentioned by Rohit, one easy method is to use TreeSet floor (another is to implement a a modified variant of Binary search. this is a more complete answer:
package test;
import java.util.TreeSet;
class CreditRange implements Comparable<CreditRange> {
long credits;
int id;
public CreditRange(int id, long credits) {
this.id = id;
this.credits = credits;
}
public CreditRange(long credits) {
this.id = -1;
this.credits = credits;
}
#Override
public int compareTo(CreditRange o) {
return credits < o.credits ? -1 : credits > o.credits ? 1 : 0;
}
#Override
public String toString() {
return "id:" + id + ", credits:" + credits;
}
}
public class Test {
public static void main(String[] args) {
TreeSet<CreditRange> set = new TreeSet<>();
set.add(new CreditRange(1, 0));
set.add(new CreditRange(2, 100));
set.add(new CreditRange(3, 500));
set.add(new CreditRange(4, 250));
System.out.println(set.floor(new CreditRange(50)));
System.out.println(set.floor(new CreditRange(300)));
System.out.println(set.floor(new CreditRange(600)));
}
}

Simulating hospital in Java (Priority Queue)

Im currently learning ADT's in school and for an assignment I have to simulate an ER in a hospital. I currently have my patient class as follows:
public class Patient implements Comparable<Patient>{
private String name;
private int condition;
public Patient( String n, int c ){
this.name = name;
this.condition = condition;
}
public String toString(){
return name;
}
public int boundary(int condition) {
if (condition > 17){
return 17;
}
else if (condition < 1) {
return 1;
}
return condition;
}
public int compareTo( Patient other ) {
if( this.condition < that.condition ) {
return -1;
}
else if( this.condition > that.condition ) {
return +1;
}
else {
return this.name.compareTo(that.name);
}
}
}
And I need to now make a class called ER()... One of many methods i have to implement have the conditions as follows:
public void addPatient(String name, int severity, Date time)
// Purpose: adds a person to the waiting list in the emergency
// room.
// Preconditions: name is not null
// severity is an integer in the range [1,17]
// time is the current time
// Postconditions: the person is added to the emergency room
// waiting list. The "priority" in the list is
// based on severity (1 being least important and
// 17 being most important) first and for patients
// with equal severity, based on time (FIFO).
My question is, where exactly would I create each patient (assign name and condition severity) and could someone help me with (please explain cuz i wanna learn, im not asking for direct code or answers) the prioritizing aspect and how to prioritize patients with same severity by time of arrival?
Thanks in advance for any help or input everyone!
Start with creating specific controller like FrontDeskController, and in this class create method e.g register/checkIn, checkOut. You will insert/remove all patients data here and collect all data in single Collection which you think its suitable for your case.
To prioritizing queue, if it possible separate the Collection you want to process, so you must sort with simple sort algorithm e.g quicksort and pass the sort data to another collection e.q Queue, Stack. i think this method good to be in ER Class.

Categories