I'm trying to understand how the comparable compareTo method sort the input. Below is the compareTo method implemented:
#Override
public int compareTo(Name n) {
int lastCmp = lastName.compareTo(n.lastName);
return (lastCmp != 0 ? lastCmp : firstName.compareTo(n.firstName));
}
The input array to the Collections.sort method is:
Name nameArray[] = {
new Name("John","Smith"),
new Name("Karl","Ng"),
new Name("Jeff","Smith"),
new Name("Tom","Rich")
};
List<Name> names = Arrays.asList(nameArray);
Collections.sort(names);
I don't understand what values are taken in to the compareTo method. (n.lastName and lastname) in which order?
The Collections.sort() method uses different algorithms to sort depending on the collection length and type (I think...)
The compareTo method should return negatives, 0, or positives if the object is less-than, equal or greater-than respectively.
the lastName variable refers to the Last Name in the Name class, composed of firstName:String and lastName:String.
The method first compares the lastName (object of type String) to the lastName of the passed object "n" (of type Name). If it is different than 0 (meaning not equal) return that value. If it is equal then compare the first name and return that.
So it is only comparing the two strings (firstName and lastName of the Name objects).
Related
This question already has answers here:
What does compareTo method return in java
(1 answer)
What do the return values of Comparable.compareTo mean in Java?
(7 answers)
Closed 10 months ago.
I'm very new to java. I know that the Java Comparable interface has only one method, which has an int return type. However, I'm not sure what I am actually doing when I want to override the compareTo method. It's important to me to understand programming and not just memorizing it.
For example, in the following code we have an int variable "spaceshipClassComparison", which is equal to "this.spaceshipClass.compareTo(other.spaceshipClass)". I know that that this method returns the values of 1,0,-1, but I don't understand what we are doing when we call compareTo() again for this.spaceship but this time with a new object and how does it turn to integer?
public class Spaceship implements Comparable<Spaceship> {
private String spaceshipClass = null;
private String registrationNo = null;
public Spaceship(String spaceshipClass, String registrationNo) {
this.spaceshipClass = spaceshipClass;
this.registrationNo = registrationNo;
}
#Override
public int compareTo(Spaceship other) {
int spaceshipClassComparison =
this.spaceshipClass.compareTo(other.spaceshipClass);
if(spaceshipClassComparison != 0) {
return spaceshipClassComparison;
}
return this.registrationNo.compareTo(other.registrationNo);
}
}
In cases when we compare obvious things like numbers, we don't need a custom compareTo method. So for example, if we want to know if 2 is greater than 1 we just use the appropriate operator: 2 > 1
However when we're dealing with things that aren't obviously comparable, like objects and spaceships (in your example), we need to explain to the compiler what criterion is used to say that one spaceship is "bigger" than another.
This is where writing a custom (#Override) compareTo method comes in. By default the compareTo method returns either 1, 0 or -1. There is no inherent meaning to these numbers, in fact they can be any numbers you like (as long as they are different). Their purpose is to match three cases when two things are compared:
thing 1 is greater than thing 2
thing 1 is equal to thing 2
thing 1 is less than thing 2
The compareTo method in your example specifies that when we compare two spaceships we are going to use the string value of their spaceshipClass. Furthermore, the compareTo method in your example uses the default implementation of comparing strings: This means that the strings are compared lexicographically (you can think of it as alphabetical).
The compareTo method is used to establish a natural ordering among the elements of a class. Here is a link which expands the concept of natural ordering.
https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html
To get back to your example, I think you're having troubles in understanding the idea of it because you're comparing two String objects which are in turn invoking their compareTo implementation which does other operations under the hood. Basically, they just perform an alphabetical comparison to establish if the current string is lower, equal or greater than the given parameter.
Let's make a simpler example with another class, though. Let's say we have a Person class with just name, last name and age, and that we want to establish its natural ordering by comparing people by their age.
class Person implements Comparable<Person> {
private String name, lastName;
private int age;
public Person(String name, String lastName, int age) {
this.name = name;
this.lastName = lastName;
this.age = age;
}
public String getName() {
return name;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
#Override
public int compareTo(Person otherPerson) {
//If the current person's age is lower than otherPerson's age than we return -1, as the current person is "lower" than the other (ordering-wise)
if (age < otherPerson.getAge()) {
return -1;
}
//If the current person's age is equal to the otherPerson's age than we return 0, as the current person is "equal" to the other (ordering-wise)
if (age == otherPerson.getAge()) {
return 0;
}
//Here, there are no other cases left so the current person's age is greater than the otherPerson's age, so we return 1.
return 1;
}
public static void main(String[] args) {
Person p1 = new Person("Matt", "O'Brien", 20);
Person p2 = new Person("Matt", "O'Brien", 25);
Person p3 = new Person("George", "Lucas", 25);
System.out.println(p1.compareTo(p2)); //Prints -1 because 20 is lower than 25
System.out.println(p2.compareTo(p1)); //Prints 1 because 25 is greater than 20
System.out.println(p2.compareTo(p2)); //Prints 0 because 20 is equal to 20 even though we're comparing different people, because in the comprateTo we're only confronting the age
}
}
What you're doing in your compareTo example is basically establishing a natural ordering between Spaceship elements, first by their class and then by their number. In fact, if the alphabetical order of their class is different from 0, then this value is immediately returned. Otherwise, if their class is the same, another comparison is performed (by registration number) and its value returned.
public int compareTo(Spaceship other) {
//Saving the comparison value between the spaceships' class
int spaceshipClassComparison =
this.spaceshipClass.compareTo(other.spaceshipClass);
//If they are already different by class we return the ordering value (no point in comparing also the number)
if(spaceshipClassComparison != 0) {
return spaceshipClassComparison;
}
//If the spaceships have the same class then we return the comparison between their registration number
return this.registrationNo.compareTo(other.registrationNo);
}
This question already has answers here:
Collections.sort with multiple fields
(15 answers)
Closed 6 years ago.
public int compareTo(Name other) {
int result = this.familyName.compareTo(other.familyName);
if (result == 0) {
result = this.firstName.compareTo(other.firstName);
}
return result;
}
I can't comprehend the meat of the code, how it is used to compare names.
If the family names are the same, then it compares the first name.
Essentially "grouping by" family name.
This is the compareTo method of a class implementing the Comparable (see https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html) interface. The return value of compareTo is defined to be 0 if the objects are identical, < 0 if the argument is lexicographically greater, and > 0 if the argument is less.
The result of the comparison of the Name object you have here is delegated to the compareTo method of the familyName attribute. That means the familyName attribute of the current Name object is compared to the argument's familyName attribute. The second compareTo check is only done if the familyName attributes of both Name object instances are identical. If that's the case, the firstName is compared instead.
I was checking the string comparison methods used for string compsrsion and explore the string class in the decomplier and come to know that there are basically four methods
equals()
equalsIgnoreCase()
compareTo()
compareToIgnore()
Now I want to know the difference between two methods that we use they are equals() and compareTo() , basically please advise why string class had kept both these methods ..
String tv = "Bravia";
String television = "Bravia";
// String compare example using equals
if (tv.equals(television)) {
System.out.println("Both tv and television contains same letters and equal by equals method of String");
}
// String compare example in java using compareTo
if (tv.compareTo(television) == 0) {
System.out.println("Both tv and television are equal using compareTo method of String");
}
output :-
Both tv and television contains same letters and equal by equals method of String
Both tv and television are equal using compareTo method of String
equals() returns a boolean; true/false. Is string A equal to B?
compareTo() returns an integer, representing not only whether the strings are equal, but which one is "lower" than the other - with "lower" defined as the natural alphabetical ordering.
For two strings a and b, a.equals(b) is true if an only if a.compareTo(b) is 0.
For example:
String a = "String1";
String b = "String2";
a.compareTo(b) will return a negative integer (not necessarily -1!), because, alphabetically, the string "String1" is lower than "String2"; if you were to sort the two strings in ascending order, "String1" would come first. Also, a.equals(b) will return false, because the strings are not equal.
However:
String a = "Example";
String b = "Example";
In this case, a.compareTo(b) will return 0 (because the strings are equal), and a.equals(b) will return true (again, because the strings are equal).
With respect to the "ignoreCase" variants:
String a = "String1";
String b = "string1";
In this case, a.compareToIgnoreCase(b) will return 0; that's because, when case is ignored, the two strings are identical. Also, a.equalsIgnoreCase(b) will return 0, for the same reason.
equals and equalsIgnoreCase return a boolean value that say "one is either equal to another, or is not"
compareTo and compareToIgnoreCase() return a tristate integer, 0, -1 or 1
0 if they're equal comparing each ordinally
1 if the
argument to compareTo*() is greater in ordinal than the object you invoke compareTo*() on
-1 if the argument to compareTo*() is lesser in
ordinal than the object you invoke compareTo*() on.
Strings implement Comparable interface and then its bound to implement compareTo method.
Camparable interface
it facilitates ordering of the object when they are contained in any sorted collection. So when you will put your string in any sorted collection(like TreeSet), how will you tell java how to sort your objects. that's where coompareTo() method comes in seen. it is used by collection to sort your object.
String tv = "Bravia";
String television = "Bravia";
// String compare example using equals
if (tv.equals(television)) {
System.out.println("Both tv and television contains same letters and equal by equals method of String");
}
// String compare example in java using compareTo
if (tv.compareTo(television) == 0) {
System.out.println("Both tv and television are equal using compareTo method of String");
}
if (tv.compareTo(television) < 0){
System.out.println("tv comes before using compareTo method of String");
}
if (tv.compareTo(television) > 0){
System.out.println("tv comes after using compareTo method of String");
}
Both methods are needed. String inherits equals from Object, and compareTo is required when implementing the Comparable interface.
compareTo(): return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object. from compareTo()
equals(): The equals() method compares two objects for equality and returns true if they are equals else return false source here
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);
}
}
I tried the following simple test.
class ZiggyTest{
public static void main(String[] args){
List<Cities> cities3 = new ArrayList<Cities>();
Cities city = new Cities("London");
cities3.add(new Cities("Manchester"));
cities3.add(new Cities("Glasgow"));
cities3.add(new Cities("Leeds"));
cities3.add(city);
cities3.add(new Cities("Leicester"));
cities3.add(new Cities("Croydon"));
cities3.add(new Cities("Watford"));
System.out.println("IndexOf(new Croydon) "
+ cities3.indexOf(new Cities("Croydon")));
System.out.println("IndexOf(city) "
+ cities3.indexOf(city));
}
}
class Cities implements Comparable<Cities>{
String title;
Cities(String aTitle){
this.title = aTitle;
}
public String getTitle(){
return title;
}
public String toString(){
return "Title : " + title;
}
public int compareTo(Cities c){
return title.compareTo(c.getTitle());
}
}
The output of the above test is
IndexOf(new Croydon) -1
IndexOf(city) 3
I understand why the second line is producing 3 but I don't understand why the first line is not finding the new one with title="Croydon".
The API describes the indexOf method as one that
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
I think the API is saying that if the object is null then it will return the index of the first occurrence of a null object from the list. If it is not null it will return the index of the first occurrence where the passed in object equals method returns true.
Shouldn't the the object created as cities3.indexOf(new Cities("Croydon") be equal to the object added previously as cities3.add(new Cities("Croydon"));?
Redefine equals instead of compareTo if you want perform search operations.
By default indexOf compares using equals operation, and in your case equals not redefined, that means you have comparison by references. When you create new City object with the same name you have another reference to object, so equals return false.
P.S. If you are using object that describe city, preferable name for class City not Cities
In Swift 5.3, if your object inherits from NSObject, you'll need to do this:
The method name is "isEqual"
public override func isEqual(_ object: Any?) -> Bool {
if let myObj = object as? MyObj {
return myObj.someProperty == self.someProperty
}
return false
}