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.
Related
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);
}
}
public int compareTo(Person p) {
int res = 1;
String personStr = p.getId();
String thisId = this.getId();
if(thisId.equals(personStr)){
res = 0;
}
else if(thisId.compareTo(personStr)){
res = -1;
}
return res;
}
A quite simple compareTo method I have implemented but I don't get the error message. The condition in the else if statemint gives me a message saying that it can't convert from int to boolean. I get that, but the thing is that I'm using netiher. I just want to compare 2 simple strings, why does this happen?
What you should notice is that the interface 'compareTo' is returning an int 'public int compareTo' being the sign
if statements rely on a boolean value, however you use thisId.compareTo(personStr) which will return an integer, just like the method you are creating.
Your first if statement is fine - 'equals' returns a boolean. However the second does not, it will likely return either a -1, a 0 or a 1.
but the thing is that I'm using netiher
Are you sure about that?
This results in an int:
thisId.compareTo(personStr)
But you're using it as a Boolean:
if (yourResult)
An if statement requires a boolean, it can't just be used on any value. For example, consider the difference between this:
if (value == 1)
and this:
if (value)
In some languages you can get away with that. Some languages assign degrees of "truthiness" to all types, allowing you to use them in boolean expressions. Java is not one of them. You have to explicitly define your boolean logic in Java:
if(thisId.compareTo(personStr) > 0) // or whatever your logic should be
if you just want to compare those 2 strings why not use
public int compareTo(Person p) {
String personStr = p.getId();
String thisId = this.getId();
return thisId.compareTo(personStr);
}
I have created my own class of which I want to create my TreeSet. My class looks like this :
class mytree implements Comparable
{
int line_no;
line_segment line[];
public int compareTo(Object obj)
{
tree t = (tree)obj;
if(this.line_no == t.line_no)
return 0;
if(this.line[line_no]>t.line[line_no])
return 1;
else
return -1;
}
}
I am defining new objects of the class and then inserting them into the TreeSet.
In cases I am finding out
values like
mytree up = tree.lower(n1);
mytree down = tree.higher(n2);
but if I try to check whether the values of up and down exist in the tree then it sometimes happen that the tree says that the values don't exists in the tree and sometimes it says the values do exist. Though I have handled the case of 0 in compare method what could be the possible error in my creating of the tree.
There are many things wrong in this code. First of all, you're not respecting the Java conventions at all. Second, you're not using generics, as if we were still in 2004, when Java 5 didn't exist yet. Third, your class doesn't represent a tree, so it shouldn't be named mytree. Fourth, your compareTo() method is wrong. It's supposed to be symmetric:
A > B <==> B < A
If A and B's line[line_no] are equal, then if you compare them with A.compareTo(B), the comparison method will return -1. And if you compare them with B.compareTo(A), it will return -1 as well. So you have A < B and B < A at the same time.
if(this.line_no == t.line_no)
return 0;
if(this.line[line_no]>t.line[line_no])
return 1;
You're comparing two different things in these two checks. I'd expect you should be comparing the same thing, e.g.
if(this.line_no == t.line_no)
return 0;
if(this.line_no > t.line_no)
return 1;
or
// also note you probably mean t.line[t.line_no] instead of t.line[line_no]
if(this.line[line_no] == t.line[t.line_no])
return 0;
if(this.line[line_no]>t.line[t.line_no])
return 1;
This question already has answers here:
"int cannot be dereferenced" in Java
(8 answers)
Closed last year.
I'm doing some assignment work and I've struck a problem.
I've been given this example code:
public class PersonNameComparator implements Comparator<Person>{
public int compare(Person p1, Person p2) {
int retValue = p1.getName().compareTo(p2.getName());
if (retValue != 0)
return retValue;
else if (p1.getAge() < p2.getAge())
return -1;
else if (p1.getAge() > p2.getAge())
return 1;
else
return 0;
}
}
However, when I try to do this, this happens:
public class DVDComparator implements Comparator <DVD> {
public int compare(DVD d1,DVD d2)
{
int stars1 = d1.getNoOfStars().compareTo(d2.getNoOfStars());
//ERROR - int cannot be dereferenced.
Any ideas?
You get this error message since getNoOfStars() returns a primitive int and there is no method compareTo() defined for primitive types.
If you're using Java SE 7 you can use something like this:
public class DVDComparator implements Comparator <DVD> {
public int compare(DVD d1,DVD d2){
return Integer.compare(d1.getNoOfStars(), d2.getNoOfStars());
}
}
You don't need to call a method to compare primitive ints. In fact, as you've discovered, you can't.
Just use the normal <, >, and == operators to compare ints.
Just make sure to follow the contract of compare -- return an int less than 0, equal to 0, or greater than 0, if d1 is "less than" d2, if d1 is "equal to" d2, or d1 is "greater than" d2, respectively.
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
int being a primitive is not an object and thus does not have any methods. So when you try and call .compareTo on it, you get an error.
To compare ints, you can use the standard comparison operators < > ==, or you could wrap it in an Integer Object and use the compare method as you are doing now. Although the former is favorable.
// If Person.getName() returns a string then you could simply do the following to // implement Comparable:
public class PersonNameComparator implements Comparator<Person>{
public int compare(Person p1, Person p2) {
return p1.getName() - p2.getName(); // It's the ninja way to do it
}
}
You can find the reason for above error through this link.
You can use one of following approaches which are simple to understand. (sorting in ascending order)
if(d1.getNoOfStars() != d2.getNoOfStars())
return d1.d1.getNoOfStars() - d2.getNoOfStars();
or
if(d1.getNoOfStars() != d2.getNoOfStars())
return d1.d1.getNoOfStars() > d2.getNoOfStars() ? 1 : -1;
Currently I am writing a compareTo method for quadratic functions in the form: ax^2 + bx + c.
a, b, c are integer coefficients that are passed to the class through the constructor.
In the compareTo method, I am supposed to first compare the a-coefficients between two functions, but if they are equal, I compare the b-coefficients. If the b's are equal, I compare the c's.
The method that I came up for this ended up being pretty ugly:
public int compareTo(QuadraticFunction other)
{
if (a > other.a)
return 1;
else if (a < other.a)
return -1;
else if (b > other.b)
return 1;
else if (b < other.b)
return -1;
else if (c > other.c)
return 1;
else if (c < other.c)
return -1;
else
return 0;
}
So I was wondering, if you have these "tiered" systems of comparisons (like compare a's before b's before c's), what's the best way to implement them? I can't imagine writing a method like mine if you have to go through 10+ variables.
For an arbitrary number of coefficients (all of the same type), you should store them in a List (or something similar), rather than individually-named member variables. That allows you to convert your example code into an iteration.
The Guava Libraries provide an extremely nice tool to do this called ComparisonChain.
Your code would look something like this:
import com.google.common.base.ComparisonChain;
...
public int compareTo(QuadraticFunction other) {
return ComparisonChain.start()
.compare(a, other.a)
.compare(b, other.b)
.compare(c, other.c)
.result();
}
For readability, and to use the built-in compare methods for a, b, c, I would refactor to this:
public int compareTo(QuadraticFunction other) {
if (a.equals(other.a)) {
if (b.equals(other.b))
return c.compareTo(other.c);
return b.comapreTo(other.b);
}
return a.compareTo(other.a);
}
This code assumes the fields are Number. If they are a primitive, either convert them to wrapped type or change a.equals(b) toa == band changea.compareTo(b)toa - b`.
Also note that when an if returns, there is never a need for an else - it's redundant, so remove it.
You can use an idiom like the below which breaks the comparison into clear sections by field, only requires one test per field, and uses the signum method to produce the return values.
Note, the subtraction below works for int, short, char, or byte fields.
For long, float, and double fields you have to use separate checks for < and == to avoid overflow/underflow, and loss of precision due to rounding. Be careful of NaN too when comparing floating point values.
For Comparable fields, you can just set delta to the result of compareTo after using separate conditions to handle null.
long delta = ((long) a.field1) - b.field1;
if (delta != 0) { return Long.signum(delta); }
delta = ((long) a.field2) - b.field2;
if (delta != 0) { return Long.signum(delta); }
...
return 0;