I am learning about arrays, and basically I have an array that collects a last name, first name, and score.
I need to write a compareTo method that will compare the last name and then the first name so the list could be sorted alphabetically starting with the last names, and then if two people have the same last name then it will sort the first name.
I'm confused, because all of the information in my book is comparing numbers, not objects and Strings.
Here is what I have coded so far. I know it's wrong but it at least explains what I think I'm doing:
public int compare(Object obj) // creating a method to compare
{
Student s = (Student) obj; // creating a student object
// I guess here I'm telling it to compare the last names?
int studentCompare = this.lastName.compareTo(s.getLastName());
if (studentCompare != 0)
return studentCompare;
else
{
if (this.getLastName() < s.getLastName())
return - 1;
if (this.getLastName() > s.getLastName())
return 1;
}
return 0;
}
I know the < and > symbols are wrong, but like I said my book only shows you how to use the compareTo.
This is the right way to compare strings:
int studentCompare = this.lastName.compareTo(s.getLastName());
This won't even compile:
if (this.getLastName() < s.getLastName())
Use
if (this.getLastName().compareTo(s.getLastName()) < 0) instead.
So to compare fist/last name order you need:
int d = getFirstName().compareTo(s.getFirstName());
if (d == 0)
d = getLastName().compareTo(s.getLastName());
return d;
The compareTo method is described as follows:
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object.
Let's say we would like to compare Jedis by their age:
class Jedi implements Comparable<Jedi> {
private final String name;
private final int age;
//...
}
Then if our Jedi is older than the provided one, you must return a positive, if they are the same age, you return 0, and if our Jedi is younger you return a negative.
public int compareTo(Jedi jedi){
return this.age > jedi.age ? 1 : this.age < jedi.age ? -1 : 0;
}
By implementing the compareTo method (coming from the Comparable interface) your are defining what is called a natural order. All sorting methods in JDK will use this ordering by default.
There are ocassions in which you may want to base your comparision in other objects, and not on a primitive type. For instance, copare Jedis based on their names. In this case, if the objects being compared already implement Comparable then you can do the comparison using its compareTo method.
public int compareTo(Jedi jedi){
return this.name.compareTo(jedi.getName());
}
It would be simpler in this case.
Now, if you inted to use both name and age as the comparison criteria then you have to decide your oder of comparison, what has precedence. For instance, if two Jedis are named the same, then you can use their age to decide which goes first and which goes second.
public int compareTo(Jedi jedi){
int result = this.name.compareTo(jedi.getName());
if(result == 0){
result = this.age > jedi.age ? 1 : this.age < jedi.age ? -1 : 0;
}
return result;
}
If you had an array of Jedis
Jedi[] jediAcademy = {new Jedi("Obiwan",80), new Jedi("Anakin", 30), ..}
All you have to do is to ask to the class java.util.Arrays to use its sort method.
Arrays.sort(jediAcademy);
This Arrays.sort method will use your compareTo method to sort the objects one by one.
Listen to #milkplusvellocet, I'd recommend you to implement the Comparable interface to your class as well.
Just contributing to the answers of others:
String.compareTo() will tell you how different a string is from another.
e.g. System.out.println( "Test".compareTo("Tesu") ); will print -1
and System.out.println( "Test".compareTo("Tesa") ); will print 19
and nerdy and geeky one-line solution to this task would be:
return this.lastName.equals(s.getLastName()) ? this.lastName.compareTo(s.getLastName()) : this.firstName.compareTo(s.getFirstName());
Explanation:
this.lastName.equals(s.getLastName()) checks whether lastnames are the same or not
this.lastName.compareTo(s.getLastName()) if yes, then returns comparison of last name.
this.firstName.compareTo(s.getFirstName()) if not, returns the comparison of first name.
You're almost all the way there.
Your first few lines, comparing the last name, are right on track. The compareTo() method on string will return a negative number for a string in alphabetical order before, and a positive number for one in alphabetical order after.
Now, you just need to do the same thing for your first name and score.
In other words, if Last Name 1 == Last Name 2, go on a check your first name next. If the first name is the same, check your score next. (Think about nesting your if/then blocks.)
Consider using the Comparator interface described here which uses generics so you can avoid casting Object to Student.
As Eugene Retunsky said, your first part is the correct way to compare Strings. Also if the lastNames are equal I think you meant to compare firstNames, in which case just use compareTo in the same way.
if (s.compareTo(t) > 0) will compare string s to string t and return the int value you want.
public int Compare(Object obj) // creating a method to compare {
Student s = (Student) obj; //creating a student object
// compare last names
return this.lastName.compareTo(s.getLastName());
}
Now just test for a positive negative return from the method as you would have normally.
Cheers
A String is an object in Java.
you could compare like so,
if(this.lastName.compareTo(s.getLastName() == 0)//last names are the same
I wouldn't have an Object type parameter, no point in casting it to Student if we know it will always be type Student.
As for an explanation, "result == 0" will only occur when the last names are identical, at which point we compare the first names and return that value instead.
public int Compare(Object obj)
{
Student student = (Student) obj;
int result = this.getLastName().compareTo( student.getLastName() );
if ( result == 0 )
{
result = this.getFirstName().compareTo( student.getFirstName() );
}
return result;
}
If you using compare To method of the Comparable interface in any class.
This can be used to arrange the string in Lexicographically.
public class Student() implements Comparable<Student>{
public int compareTo(Object obj){
if(this==obj){
return 0;
}
if(obj!=null){
String objName = ((Student)obj).getName();
return this.name.comapreTo.(objName);
}
}
Related
I am trying to check the values of a comparable method and assign the 1 and -1 value to true and false. I made a simple if else statement that does just that but I want to make it inside of a method so I can use it multiple times in my main method. When I try to do this I get an error that my compareTo method (in another class) is "undefined for the type Object".
Here is my code for both the compareTo method and my attempt of using this in my test class.
public int compareTo(FPNumber o) {
if ((exp == o.exp) && (fraction - o.fraction < SMALL))
return 1;
else if ((exp == o.exp) || (fraction - o.fraction > SMALL))
return -1;
else
return 0;
}
public String compare(Object FP1, Object FP2) {
if (FP1.compareTo(FP2) == 1)
System.out.println("true");
else if (FP1.compareTo(FP2) == -1)
System.out.println("false");
else
System.out.println("error");
}
Let me start by a simple example using raw values, and then expand it to use objects.
Suppose you have two variables x and y that hold integer values. If I ask you, how do you know if the values for these variables are equal? The question is answered by simple math: if the values of the two variables are equal, the difference between the two must be zero. For example, 5 - 5. In this case, the difference is zero because both variables hold the value of positive 5.
What if they are different? Let x = 5 and y = 13.
x - y = -8 (this means that x < y)
y - x = 8 (same as above)
As you can see, when the values are different, it is not always going to be 1 or -1. This is important when you are comparing more than two values. Let's introduce z = 20. If comparing x to y and x to z and the result was -1 on both comparisons, the implication is that y and z must be equal but they are not.
What about when comparing objects? It is the same principle. Even when an object holds multiple variables, you must decide a hierarchy to determine which variable is more or less important in the comparison. Consider the following example
public class Person implements Comparable<Person> {
private String firstName;
private String lastName;
private int age;
...
public int compareTo(Person other) {...}
}
I can decide that, for my system, when comparing two Person objects, I must check first the last name, then the first name, and lastly the age.
public int compareTo(Person other) {
int i = lastName.compareTo(other.lastName);
if (i != 0) return i;
i = firstName.compareTo(other.firstName);
if (i != 0) return i;
return Integer.compare(age, other.age);
}
Basically, if the last names are the same (i == 0), it will compare the first names. Then if the first names are the same, it will compare the ages. At any point, if the values are different, the difference will be returned. Again, not a 1 or -1. So basically, to convert the results to boolean, the logic is
public boolean compare(Person person, Person other) {
if (person.compareTo(other) == 0) return true;
else return false;
}
By the way, your original code has a compilation error because your compare method should return a String and it returns void. Instead of using System.out.print() inside your method, like you have now, you should print out the output of the method.
public String compare(Object FP1, Object FP2) {
if (FP1.compareTo(FP2) == 1)
return "true";
else if (FP1.compareTo(FP2) == -1)
return "false";
else
return "error";
}
...
System.out.println(compare(FP1, FP2));
UPDATE: I forgot to mention before that, essentially, the compare function I included here is serving basically the same function as the equals() method. Also, because this function is provided by a third party, it is sort of what a Comparator should do. Because of that, it should be done following best practices of what a Comparator should do. For my Person comparator, you may have two Comparators: one that compares age and one that compare names.
I'm new to Java and try to learn Java collections and try to sort arraylist with comparable interface. I follow some tutorials and I'm unable to understand what is happen within the compareto() method here. this is my code.
Student.java
package arraylistexample;
public class Student implements Comparable<Student>{
private String studentName;
private int age;
private int rollno;
public Student(String studentName, int age, int rollno){
this.studentName=studentName;
this.age=age;
this.rollno=rollno;
}
public String getStudent(){
return studentName;
}
public int getAge(){
return age;
}
public int getRollno(){
return rollno;
}
public void setStudent(String Student){
studentName=Student;
}
public void setAge(int age){
this.age=age;
}
public void setRollno(int rollno){
this.rollno=rollno;
}
public int compareTo(Student compares) {
int compareage=((Student)compares).getAge();
/* For Ascending order*/
return this.age-compareage;
}
public String toString() {
return "[ rollno=" + rollno + ", name=" + studentName + ", age=" + age + "]";
}
}
ArrayListSorting.java
package arraylistexample;
import java.util.*;
public class ArrayListSorting {
public static void main(String[] args){
ArrayList<Student> obj=new ArrayList<Student>();
obj.add(new Student("Peter", 27,1));
obj.add(new Student("John",26,7));
obj.add(new Student("Jack",21,5));
Collections.sort(obj);
for(Student str:obj){
System.out.println(str);
}
}
}
The problem is I can't understand how caompareto() method works in here. I googled and read many tutorials. But didn't get clear idea. Can anyone help me.
How compareTo works
If the two elements (a,b) being compared are already in the right order, a.compareTo(b) will return a value that is <= 0, so nothing has to happen.
If they aren't in the right order, the return value is > 0, indicating that they must be interchanged.
So in your case student object passed in your compareTo method whose age is greater than your reference object (this) student age they get interchanged to default sorting which is ascending.
Writing a compareTo method for your class lets you specify what criteria your program will use to decide which of two objects of that class should come first in order.
If you don't write a compareTo method for your class, then your program has no way of knowing which order to put two objects in - and therefore it has no way of sorting a whole lot of objects.
But if you write a compareTo method in your class, AND indicate that your class implements the Comparable interface, then your program will be able to sort any number of objects of that class.
What that means is that you have to decide what order you want your Student objects to appear in. Maybe you want them sorted by roll number. So you write your compareTo accordingly, like this.
public int compareTo(Student other) {
return rollno - other.rollno;
}
This particular method will return
a positive number if the current student has a higher roll number than the student called other,
a negative number if the current student has a lower roll number than the student called other.
zero if you try to compare a student to itself.
So it meets all the criteria that a compareTo method has to meet; and it can be used to sort a bunch of students. The actual algorithm that's used for the sort is buried in the Collections.sort method. You don't need to know what it is - you only need to know that it uses your compareTo method in the course of doing the sort.
From Oracle docs of the compareTo method:
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
When you implement the method for your own composite-object, you are creating a way to compare those objects.
For example:
A Student named "Peter" and a 'Student named "Greg" - who is bigger/smaller?
That's up to you to decide... You can either choose alphabetical order of name, or ages, or any other component/member/logic to decide.
Edit:
As mentioned by Eran in the comments, the way Collections.sort works is using the compareTo method. From the docs:
orts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
For sorting collections a compareTo function is used to see if object1 is bigger or smaller than object2 by doing
object1.compareTo(object2)
According to documentation of Intger Object's compareTo
the value 0 if this Integer is equal to the argument Integer; a value
less than 0 if this Integer is numerically less than the argument
Integer; and a value greater than 0 if this Integer is numerically
greater than the argument Integer (signed comparison).
You can find a similar documentation for String Object. This same practice is used for all objects generally.
So, the idea is that the compareTo method in your class should basically return
<0 if object1 < object2
=0 if object1 = object2
>0 if object1 > object2
Using this the Collections API can sort objects.
So, in your case you can see
public int compareTo(Student compares) {
int compareage=((Student)compares).getAge();
/* For Ascending order*/
return this.age-compareage;
}
is used where it is allowing comparison of students based on their age.
The program sorts the array in ascending order but on swapping id and compareid in the return statement the array sorts in descending order but it has no effect on the output of System.out.println(e[1].compareTo(e[0])); it returns 1 in both cases. Why is it so?
package example;
import java.util.Arrays;
class Example implements Comparable<Example> {
int id;
public int compareTo(Example ob) {
int compareid = ob.id;
return Integer.compare(id, compareid); // problem
}
}
class comparableinterface {
public static void main(String args[]) {
Example e[] = new Example[3];
e[0] = new Example();
e[0].id = 2;
e[1] = new Example();
e[1].id = 3;
e[2] = new Example();
e[2].id = 0;
Arrays.sort(e);
for (Example temp : e) {
System.out.println(temp.id);
}
System.out.println(e[1].compareTo(e[0]));
}
}
Because your comparison is being performed after you have sorted the array, and Arrays.sort(e) changes the contents of the array e.
Move
System.out.println(e[1].compareTo(e[0]));
to before the sort, and it will behave as you expected.
The result of compareTo reflects a certain order between the object and the argument. This will always be +1 between the first and second in a sorted array, sorted according to whatever is expressed by compareTo.
It is not an indication of the numeric relation!
You are using Integer.compare(id,compareid) in your overrided compareTo(Example ob) method, and for your information,
Integer.compare(id,compareid) returns the value 0 if id == compareid; a value less than 0 if id < compareid; and a value greater than 0 if id > compareid.
And you are calling compareTo(Example ob) after sorting the array, this is why the method always returning 1.
Try calling compareTo(Example ob) before sorting the array.
compareTo method is referred to as its natural comparison method.
The natural ordering for a class C is said to be consistent with
equals if and only if e1.compareTo(e2) == 0 has the same boolean value
as e1.equals(e2) for every e1 and e2 of class C.
Ref
See also the java.utils.Arrays.mergeSort() source code to see how compareTo is used to sort an array:
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
Because in order to sort your array ascending/descending you also change your compareTo method in example to compare for < respectively > (i.e. you swap the logic in the compareTo method). That's why it gives you the same result from System.out.println(e[1].compareTo(e[0]));. Basically after the change, your compareTo does not check for "is smaller" any more but checks for "is bigger". So even though System.out.println(e[1].compareTo(e[0])); returns 1 in both cases, in the first case it tells you "e[1] is bigger than e[0]" and in the second case it tells you "e[1] is smaller than e[0]". It's kind of tricky, think about it.
You should call the compareTo() method on an instance of an Integer, not the static compare()
Try this:
int id;
public int compareTo(Example ob) {
Integer compareid = ob.id;
return compareid.compareTo(id);
}
I am attempting to sort an ArrayList based on the value of a long present within each object. After following various examples around the internet, I have come up with the following code but it is not sorting as desired (it seems to truncate parts of the object).
public static Comparator<Customer> compareSIN =
new Comparator<Customer>() {
public int compare(Customer cust1, Customer other) {
String sin1 = "" + cust1.sin;
String sin2 = "" + other.sin;
return sin1.compareTo(sin2);
}
};
Please advise me on what I am doing missing in the first snippet of code that is preventing me from sorting the objects properly.
Thanks!
From the title I assume Customer.sin is a long - and the problem is you are trying to compare them as Strings rather then by their numeric value.
(Example: 10000 is lexicographically smaller then 2 - so using Strings here is the fault)
You should use Long.compare() (Assuming java 7):
public static Comparator<Customer> compareSIN =
new Comparator<Customer>() {
public int compare(Customer cust1, Customer other) {
return Long.compare(cust1.sin,other.sin);
}
};
You do not actually need to use a compareTo() method inside your own compareTo() method.
The compare to states that it must return 0 if they are equal and negative or positive numbers for non equality.
For this reason you can compare two longs by returning the one subtracted from the other.
public int compare(Customer cust1, Customer other) {
return cust1.sin - other.sin;
}
This will as you can see, return 0 if they are equal, negative if other.sin is greater than cust1.sin and positive if cust1.sin is greater than other.sin.
You compare Strings instead of longs.
So, imagine you want to compare : "10" and "5", outcome would be "10" < "5" whereas thinking that you're working with long, you expect to get 10 > 5 ...
That can explain your issue.
I have a question about making a compareTo function in Java.
In Java, we have the String.compareTo(String) method.
However, I need to make a compareTo function with only only parameter, like: compareTo(String).
I assume that I need to use this to hold another string.
For example:
public static boolean compareTo(String word)
{
private string this.word = word;
if(word.equals(this.word))
{
return true;
}
else
{
return false;
}
}
Is this the right idea?
Do I need to create get and set functions to hold first word to compare with second word?
Thanks
To compare two objects, you need to implement the Comparable interface. As part of the implementation, you will write your own compareTo() method. This method compares your current object with the object being passed.
public MyObj implements Comparable<MyObj> {
...
public int compareTo(MyObj anObj) {
// if your obj greater than anObj, return 1
// if equal, return 0
// else return -1
}
}
Further down in your code, you can then do --
`MyObj anObj = new MyObj();
MyObj anObj1 = new MyObj();
// anObj.compareTo(anObj1) ....
// This will also be useful if you have a collection of MyObjs.
Collections.sort(arrayListOfMyObjs);
That's not the right idea in many ways...
You cannot use this in a static function.
You cannot add a visibility declaration to a local variable of a function.
There is no string but String in Java.
You make this.word equals to word then check if they are equal...
You don't need to do if/else to return a boolean: just do return x.equals(y); (not necessarily wrong, but that's a personal pet peeve...).
compareTo, the classical one, isn't equals, but returns -1, 0 or 1 depending if one object is lower, equals or higher than the other.
Revise your lessons... :-)
In your code, the method compareTo is static, so you can not use "this."
I suggest you'd better NOT make compareTo method static.