Java comparator Issue - java

I'm taking in all the information from an MySQL database table using a resultset and adding all the values into an array
public void populateQueueFromDB() {
// create priority queue
try {
String url = "jdbc:mysql://localhost:3306/project";
Connection conn = DriverManager.getConnection(url, "root", "nbuser");
PreparedStatement stmt = conn.prepareStatement("SELECT user_id,s_date,e_date,d_date,department,projectname,projectapplication,priority,cores,disk_space,analysis FROM booking");
ResultSet rs;
rs = stmt.executeQuery();
//List<JobRequest> jobList = new ArrayList<JobRequest>();
while (rs.next()) {
JobRequest job = new JobRequest();
User user = new User();
user.setUserID(rs.getString("user_id"));
job.setUserID(user.getUserID()); // changes the /user id to the job.setuser id so can call for my queue print.
job.setStartDate(rs.getString("s_date"));
job.setEndDate(rs.getString("e_date"));
job.setDeadDate(rs.getString("d_date"));
job.setDepartment(rs.getString("department"));
job.setProjectName(rs.getString("projectname"));
job.setProjectApplication(rs.getString("projectapplication"));
job.setPriority(rs.getInt("priority"));
job.setCores(rs.getInt("cores"));
job.setDiskSpace(rs.getInt("disk_space"));
job.setAnalysis(rs.getString("analysis"));
schedulerPriorityQueue.addJob( job );
}
schedulerPriorityQueue.printQueue();
conn.close();
} catch (Exception e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
}
from here I go off and call my comparator to order the data, depending on priority of being either 1,2,3 then sort the queue. some other bits of code naming etc but essentially it sends me to the comparator
public class JobQueueComparator implements Comparator<JobRequest> {
#Override
public int compare(JobRequest object1, JobRequest object2) {
if(object1.getPriority() < object2.getPriority()){
return 1;
} else {
return -1;
}
}
}
But the output I'm getting from the comparator is ordering it in priority 3, 1 then 2. I've adapted this from example online but I don't understand the returns on comparator examples I've seen.
How would I be able to change that comparator to sort my priorities, 1 being the most important, 3 being the least. I made sure I'm printing out the output after adding all the result sets into the array so I know it's working as it's changed my ordering around, just dont know how to order it how I want.
Thanks
EDIT:
schedulerPriorityQueue
public class Queue {
private Comparator<JobRequest> comparator = new JobQueueComparator(); //calls my comparator
private PriorityQueue< JobRequest> scheduledJobs = new PriorityQueue<JobRequest>(100, comparator);
public void addJob(JobRequest job) {
// now add job to priority queue
scheduledJobs.add(job); // add jobs from the resultset into queue
}

Make it easy on yourself and use Integer and its compareTo method.
Your comparator method would look like this
#Override
public int compare(JobRequest object1, JobRequest object2) {
Integer iO1 = Integer.valueOf(object1.getPriority());
Integer iO2 = Integer.valueOf(object2.getPriority());
return -(i01.compareTo(iO2));
}
Assuming getPriorityreturns a int or String.

Simply swap the signs on the compare method. This will reverse the order.
public int compare(JobRequest object1, JobRequest object2) {
if(object1.getPriority() < object2.getPriority()){
return -1;
} else {
return +1;
}
}

You should return 0 from the comparator if the two objects are equal, an integer less than 0 if object 1 < object 2, and an integer greater than 0 if object 1 > object 2. Currently the JobQueueComparator never returns 0. Try the following:
public class JobQueueComparator implements Comparator<JobRequest> {
#Override
public int compare(JobRequest object1, JobRequest object2) {
return object1.getPriority() - object2.getPriority();
}
}
See the Comparator documentation for more details.

You are missing the case where the priorities are equal. I would use something like this:
public class JobQueueComparator implements Comparator<JobRequest> {
#Override
public int compare(JobRequest object1, JobRequest object2) {
return -(object1.getPriority() - object2.getPriority());
}
}
This would work if you take into consideration the priority order like this: 1, 2, 3.

Related

Using comparator for several characteristics in java

I have a list to be sorted but it cannot be done if values are represented as strings. Example:
to sort: OB123, OB1212, Maintenance, Daily check, OB123
desired result: Daily check, Maintenance, OB123, OB123, OB1212
if values are strings result is: Daily check, Maintenance, OB1212, OB123,OB123
Therefore I need to use comparator to first sort aircraft numbers such OB123 by their carrier(OB), than by their number (123) and sometimes suffix (""). And after that I would like to compare the whole name with all the rest values as "daily check" etc.
So far I can sort only flight Ids:
#Override
public int compareTo(FlightNumberDisplay toCompare) {
int result = _carrier.compareTo(toCompare.getCarrier());
if (result == 0) {
result = _number.compareTo(toCompare.getNumber());
if (result == 0) {
result = _suffix.compareTo(toCompare.getSuffix());
}
}
return result;
}
So since "Daily check" has also carrier+number+suffix representation it is sorted according to it. The question is how to sort them according to their names.
Well, you can make a comparison checking for numbers in the strings:
FlightComparator.java
public class FlightComparator implements Comparator<String> {
public int compare(String arg0, String arg1) {
// both have numbers, compare them
if (containsNumber(arg0) && containsNumber(arg0)) {
Integer i1, i2;
try {
i1 = getNumber(arg0);
} catch (NumberFormatException ex) {
return 1;
}
try {
i2 = getNumber(arg1);
} catch (NumberFormatException ex) {
return -1;
}
return i1.compareTo(i2);
} else {
// no numbers
return arg0.compareTo(arg1);
}
}
private boolean containsNumber(String string) {
return string.matches(".*\\d+.*");
}
private Integer getNumber(String string) throws NumberFormatException {
return Integer.parseInt(string.replaceAll("\\D+",""));
}
}
TEST IT
public static void main(String[] args) {
String[] ss = {"OB123", "OB1212", "Maintenance", "Daily check", "OB123"};
Collections.sort(Arrays.asList(ss), new FlightComparator());
list(ss);
}
private static void list(String[] ss) {
for (String s : ss) {
System.out.println(s);
}
}
OUTPUT
Daily check
Maintenance
OB123
OB123
OB1212
DISCLAIMER
Now, while this data seems correct for what you ask, is not a real answer to your problem. Also if flight letters are different ie, OM1212, OR1212, this will only compare the numbers, so to complete solve your problem now, you can choose between
use this Comparator and compare data as shown (not using attributes)
adapt this Comparator<String> to Comparator<Flight> (best option)
CREDITS
Method getNumber created from this answer
Method containsNumber from this answer
You can extract the carrier information in another List, there you can parse it by Integer using parseInt() and then sort it.
Later you can merge both lists.

Comparable interface with many conditions

The Question is how can use comparable interface and collections.sort to do the sorting with model , production and price. Can i do these three sorting in ascending order within "public int compareto(car other)"?
For example, It will be sorted with model in alphabetical order. If model is same, then sorted with production in alphabetical order. if production is also same , then finally sorted with price in ascending order.
Thank you for attention, i stuck with this problem many days. Please help me.
public static void main(String[] args) {
ArrayList<Car> car = new ArrayList<car>();
// something ignored//
Collections.sort(car); <----------------------Problem
for (Car c : car) {
System.out.println(c);
}
}
class car implements Comparable<car>{
protected String model;
protected String production;
protected int price;
public Tablet(String model ,String production , int price)
{
this.model=model;
this.price=price;
this.production = production;
}
public int compareTo (car other)
{
?????????????????
}
}
class mini-bus extends car
{
private door;
public Tablet(String model ,String production , int price ,int door)
{
super(model , production , price);
this.door = door;
}
}
The principle is quite straightforward:
Compare the first pair of properties. If they are different, return the negative/positive compare value; otherwise...
Compare the second pair of properties. If they are different, return the negative/positive compare value; otherwise...
... (repeat for as many pairs of properties as you have) ...
Compare the last pair of properties. This is the last property, so return the compare value.
For example:
int compareModels = this.model.compareTo(that.model);
if (compareModels != 0) {
return compareModels;
}
int compareProd = this.production.compareTo(that.production);
if (compareProd != 0) {
return compareProd;
}
return Integer.compare(this.price, that.price);
Note that there is also a nice class in Guava called ComparisonChain which reduces a lot of this boilerplate logic:
return ComparisonChain.start()
.compare(this.model, that.model)
.compare(this.production, that.production)
.compare(this.price, that.price)
.result();
This stops comparing once a difference is found between any pair of properties. It will still access the subsequent properties, but that should hopefully be an irrelevantly cheap thing to do anyway.
Here is the general approach to the problem of multi-attribute sorting:
Decide on the ordered list of attributes by which you sort
For each attribute on your list, compare the values on both sides
If the result is not zero, return it right away
If the result is zero, go to the next attribute on your list
If you ran out of attributes, return zero
If the number of attributes is fixed, the "loop" on the ordered list of attributes is unrolled, i.e. each individual attribute is compared separately:
int res;
res = this.getA().compareTo(other.getA()); // e.g. model
if (res != 0) return res;
res = this.getB().compareTo(other.getB()); // e.g. production
if (res != 0) return res;
res = this.getC().compareTo(other.getC());
if (res != 0) return res;
...
// For the last attribute return the result directly
return this.getZ().compareTo(other.getZ()); // e.g. price
This should do:
public int compareTo(Car other){
if(this.getModel().compareTo(other.getModel()) != 0){
return this.getModel().compareTo(other.getModel());
}else if(this.getProduction().compareTo(other.getProduction()) != 0){
return this.getProduction().compareTo(other.getProduction());
}else{
return Integer.compare(this.getPrice(), other.getPrice());
}
}

Can you sort this ArrayList in two different ways writing your own Comparator?

I have an ArrayList of object called Course and I'm trying to sort it in 2 ways, by courseID and courseStartTime.
Edit: to clarify I mean I want to sort it by courseID at some point in time, and at another time later sort it by courseStartTime.
class Course implements Comparable<Course> {
private int courseID;
private String courseBeginTime;
#Override
public int compareTo(Course course) {
//what to return?
}
If I wrote 2 of my own comparators, one to compare courseID and the other for courseStarTime, then the compareTo() method in the class isn't used and I don't know what to return.
If I want to use the compareTo() method, I'm not sure how to write it so I can compare courseID and courseStartTime.
You can implement two different comparators.
public class CourseComparatorById implements Comparator<Course> {
#Override
public int compare(Course o1, Course o2) {
// for example - sort ascending by ID
return o1.getId() - o2.getId();
}
}
public class CourseComparatorByStartTime implements Comparator<Course> {
#Override
public int compare(Course o1, Course o2) {
// for example - sort ascending by start time
return o1.getStartTime() - o2.getStartTime();
}
}
And then use them to sort the array.
List<Course> courses = ...
Collections.sort(courses, new CourseComparatorById());
// now it's sorted by ID
Collections.sort(courses, new CourseComparatorByStartTime());
// now it's sorted by start time
You can also try the Java 8 Lambda way:
// this sorts by courseID
courseList.sort((c1, c2) -> Integer.valueOf(c1.courseID).compareTo(c2.courseID));
// this sorts by String courseBeginTime
courseList.sort((c1, c2) -> c1.courseBeginTime.compareTo(c2.courseBeginTime));
Note that is Java 8 you don't have to use Collections.sort, because the new List interface also provides a sort method
I have a feeling that this is being used for an online registration web app ...
you will probably be fetching the data source from a RDB ... It wouldnt be wise to put ALL courses in one list (one entity) and save that. I would create an object (containing courseID and courseBeginTime) for EVERY course and save them all. Then when querying, add hints to sort your entities based on whatever root parameters you have in them (like courseID or courseBeginTime), ending with a List containing objects sorted the way you want :) :)
May be you should do something like this
public class Course implements Comparator<Course> {
private int compareTime(int lhsTime, int rhsTime) {
if (lhsTime > rhsTime) {
return 1;
} else if (lhsTime == rhsTime) {
return 0;
} else {
return -1;
}
}
#Override
public int compare(Course lhs, Course rhs) {
if (lhs.id > rhs.id) {
return 1;
//Get the time object from course obj and pass to compaerTime
} else if (lhs.courseStarTime == rhs.courseStarTime) {
return compareTime(lhs, rhs);
} else {
return -1;
}
}
}

Iterating through elements of a data structure instead of Collection

My problem is this: I have an iterator class which is supposed to iterate through elements in a given data structure, <E> let's say, but what I have managed to accomplish is that when I pass in the data structure it will iterate the data structure itself.
ie. DynamicIterator it = new DynamicIterator(da);
say da is an array the output will be [1,2,3,4,5,6] instead of 1,2,3,4,5,6
My issue is, more than anything, understanding the generally accepted practice for dealing with this more than the issue itself.
edit for code:
public class X<E>
{
private final E[] rray;
private int currentIndex = 0;
public X(E... a)
{
//if the incoming array is null, don't start
if(a == null)
{
System.out.println("Array is null");
System.exit(1);
}
//set the temp array (rray) to the incoming array (a)
this.rray = a;
}
//hasNext element?
public boolean hasNext()
{
return rray.length > currentIndex;
}
//next element (depends on hasNext())
public E next()
{
if (!hasNext())
{
System.out.println("Element doesn't exist, done");
System.exit(1);
}
return rray[currentIndex++];
}
//return array
public E[] access()
{
return rray;
}
}
You won't be able to do this with a completely generic parameter <E> - how would you iterate through a Throwable, for example? What your class X does at the moment is accept any number of objects in its constructor, and then simply returns each of those objects in turn.
If you restricted the bounds of the objects passed in to implement e.g. Iterable, then you can actually start to "look inside" them and return their contents:
public class X<E> {
private final Iterator<E> it;
public X(Iterable<E> a) {
it = a.iterator();
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
return it.next();
}
}
Although this doesn't really accomplish anything different to just using a.iterator() directly instead of an instance of X...

In TreeSet, Sorting & Uniqueness of custom objects based on different properties

Below is my Student class
class Student implements Comparable {
String name;
int rollNo;
#Override
public int compareTo(Object obj) {
return ((Student)obj).name.compareTo(this.name);
}
}
latest modification: but still no getting the right result
#Override
public int compareTo(Object obj) {
Student s = (Student) obj;
if (name.equals(s.name)) { // achieving uniqueness
return 0;
} else {
if (rollNo < s.rollNo) {
return -1;
} else if (rollNo > s.rollNo) {
return 1;
} else {
// this makes `name` the second ordering option.
// names don't equal here
return name.compareTo(s.name);
}
}
}
If I create object of TreeSet<Student>, I am getting sorted list of Student objects based on unique name & ordered by name also.
But I need unique student-name in my TreeSet<Student> with order by student-rollNo.
Is it possible with Comparator? Can anybody help me, Every suggestion is appreciated.
Thanks.
UPDATE: here is the complete program:
public class Student implements Comparable {
int rollNo;
String name;
Student(String n,int rno) {
rollNo=rno;
name=n;
}
/**
* #param args
*/
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("bbb",2));
ts.add(new Student("aaa",4));
ts.add(new Student("bbb",2));
ts.add(new Student("ccc",3));
ts.add(new Student("aaa",1));
ts.add(new Student("bbb",2));
ts.add(new Student("bbb",5));
System.out.println(ts);
}
#Override
public int compareTo(Object obj) {
Student s = (Student) obj;
if (name.equals(s.name)) { // achieving uniqueness
return 0;
} else {
if (rollNo < s.rollNo) {
return -1;
} else if (rollNo > s.rollNo) {
return 1;
} else {
// this makes `name` the second ordering option.
// names don't equal here
return name.compareTo(s.name);
}
}
}
#Override
public String toString() {
return name + rollNo;
}
}
Update:2: Thank you all for your suggestions, I still need some more :)
/*
* Actual scenario is having different properties,
* So here I am just relating my actual scenario with Student class
*/
class Student implements Comparable {
// sorting required on rollNo
int rollNo;
// Unique name is required
String name;
Student(String n, int rno) {
rollNo = rno;
name = n;
}
/**
*
* #param args
*/
public static void main(String[] args) {
TreeSet<Student> tsName = new TreeSet<Student>();
// here by default, order & uniqueness by name only
tsName.add(new Student("ccc", 2));
tsName.add(new Student("aaa", 4));
tsName.add(new Student("ddd", 1));
tsName.add(new Student("bbb", 3));
tsName.add(new Student("ddd", 5));
// output: aaa:4, bbb:3, ccc:2, ddd:1
System.out.println(tsName);
// creating new comparator for student RollNo
TreeSet<Student> tsRollNo = new TreeSet<Student>(new Comparator<Student>() {
public int compare(Student stud1, Student stud2) {
return new Integer(stud1.rollNo).compareTo(stud2.rollNo);
}
});
tsRollNo.addAll(tsName);
System.out.println(tsRollNo);
// now got the desire output: ddd:1, ccc:2, bbb:3, aaa:4
}
public boolean equals(Object obj) {
// internally not used to check equality while adding objects
// in TreeSet
System.out.println("equals() for " + this + " & " + ((Student) obj));
return false;// return false/true doesn't make any sense here
}
#Override
public int compareTo(Object obj) {
Student s = (Student) obj;
// internally inside TreeSet, compareTo is used to decide
// whether two objects are equal or not,
// i.e. compareTo will return 0 for same object(here student name)
System.out.println("compareTo() for " + this + " & " + ((Student) obj));
// achieving uniqueness
return name.compareTo(s.name);
}
#Override
public String toString() {
return name + ":" + rollNo;
}
}
OUTPUT:
compareTo() for aaa:4 & ccc:2
compareTo() for ddd:1 & ccc:2
compareTo() for bbb:3 & ccc:2
compareTo() for bbb:3 & aaa:4
compareTo() for ddd:5 & ccc:2
compareTo() for ddd:5 & ddd:1
[aaa:4, bbb:3, ccc:2, ddd:1]
[ddd:1, ccc:2, bbb:3, aaa:4]
Friends, whatever I got by using two Comparators, Is it possible to
achieve the same while adding the objects ??
I cannot first Add elements & then use new comparator to achieve the desired order.
I am manipulating thousands of values so need to consider performance also.
in TreeSet It will use comparator while adding elements for sorting and unique check,
now the problem is if you use comparator for roll no you will have it sorted by roll no and unique roll nos too. you can't have both together in treeset.
I would suggest you to go for.
TreeSet here you concentrate about duplicate removal
then once you have unique data go for ArrayList and sort it in any order you want
Ordering
The answer by #ralph on using a TreeSet with a specified comparator is a good one, use that.
Design
You should wrap your concept of a "student database" inside a class that exposes and documents the correct behaviors, rather than just using a raw collection. If obtaining lists of students in particular orders is a design requirement, expose methods (perhaps returning Iterable<Student> that say that. Behind the scenes, you can do a variety of things depending on the usage pattern:
Maintain one or more Sets and or Maps sorting/indexing students by fields of interest.
On-demand in-place array sort using Arrays.sort() and a specified Comparator.
Example....
final class StudentTable {
private static final Comparator<Student> studentRollNoComparator = ...;
private final SortedSet<Student> sortedByRollNo =
new TreeSet<Student>(studentRollNoComparator);
public Iterable<Student> studentsOrderedByRollNo()
{
return sortedByRollNo;
}
//see below
public void addStudent(final Student foo) { ... }
}
Uniqueness
You need to override equals() and hashCode() on your Student class, to compare only the student name. Then you'll get uniqueness (silently) in your TreeSet. Obviously, if you do this, you need to code defensively to check to see if studentSet.contains(newStudent) before inserting newStudent, so you'll KNOW whether you've got a duplicate or not.
final class Student implements Comparable {
...
#Override
public boolean equals(Object o)
{
return o!=null &&
o (instanceof Student) &&
((Student)o).name.equals(this.name);
}
#Override
public int hashCode()
{
return name.hashCode(); // good enough for this purpose
}
}
With this in place, then your code to insert student can look like:
void addNewStudent(final Student toAdd)
{
if (studentSet.contains(toAdd)) {
throw new IllegalStateException("Student with same name as "+toAdd+" already exists.");
}
studentSet.add(toAdd);
}
Your treeset is then full of students whose names are unique, and your add operation reports a failure if not. (Throwing an exception is just one potential route, and only appropriate if adding a student with a duplicate name is ACTUALLY an exceptional condition, but you didn't say.)
You can initialize a new TreeSet with an different comparator. - So all you have to do, is to write an new Comparator (implements java.util.Comparator interface), use this comparator to initialize the a new TreeSet and then add all students to the set.
TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(allStudents);
TreeSet<Student> sortedByY new TreeSet<Student>(new YComparator());
sortedByY.addAll(allStudents);
Each Tree Set can have its own comparator for sorting, if no comparator is specifed, then the Tree Set uses the natural ordering of the set elements.
added
If you need only the name uniqe Students, then you have two ways:
Implement the comparator in a way, that it returns 0 if the name of the studens is equals (but i belive this is so kinde of hack).
First filter the students by name, and then sort them by rollNo,
A bit like this:
TreeSet<Student> sortedByRollNo new TreeSet<Student>(new RollNoComparator());
sortedByRollNo.addAll(new TreeSet<Student>(allStudends)); //this uses the native comparator to filter by uniqe name
Sorry for being to late here, here is an elegant solution:
public class OwnSortedList<T> extends TreeSet<T> {
private static final long serialVersionUID = 7109828721678745520L;
public OwnSortedList(Comparator<T> levelScoreComparator) {
super(levelScoreComparator);
}
public boolean add(T e) {
boolean existsElement = false;
Iterator<T> it = iterator();
while(it.hasNext() && !existsElement){
T nextElement = it.next();
if(nextElement.equals(e)){
// Element found
existsElement = true;
Comparator<? super T> comparator = comparator();
int compare = comparator.compare(nextElement, e);
if(compare > 0){
remove(nextElement);
super.add(e);
//element added so return true
return true;
}
}
}
if(!existsElement){
super.add(e);
}
return false;
}
}

Categories

Resources