Comparable Comparator Java - java

Here is my Code
class ComparableTest
{
public static void main(String[] args)
{
BOX[] box = new BOX[5];
box[0] = new BOX(10,8,6);
box[1] = new BOX(5,10,5);
box[2] = new BOX(8,8,8);
box[3] = new BOX(10,20,30);
box[4] = new BOX(1,2,3);
Arrays.sort(box);
for(int i=0;i<box.length;i++)
System.out.println(box[i]);
}
}
Also i have a class BOX that implements Comparable.
Now i have a few question that i would like you all to help me out with.
1.Are the methods declared in comparable interface,system defined, as in can i have any method in the comparable, or it has to be compareTo only?
2.I did not provide the implementation of Arrays.sort method, how does it sort my elements then?
3.When i use Comparator instead of comparable, then I use:
class comparatorTest
{
public static void main(String args[])
{
Student[] students = new Student[5];
Student[0] = new Student(“John”,”2000A1Ps234”,23,”Pilani”);
Student[1] = new Student(“Meera”,”2001A1Ps234”,23,”Pilani”);
Student[2] = new Student(“Kamal”,”2001A1Ps344”,23,”Pilani”);
Student[3] = new Student(“Ram”,”2000A2Ps644”,23,”Pilani”);
Student[4] = new Student(“Sham”,”2000A7Ps543”,23,”Pilani”);
// Sort By Name
Comparator c1 = new studentbyname();
Arrays.sort(students,c1);
for(int i=0;i<students.length;i++)
System.out.println(students[i]);
}
}
//In the above code, studentbyname implements comparator, but box stil implements comparable .i.e
class studentbyname implements comparator
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return s1.getName().compareTo(s2.getName());
}
}
Now i am doing Arrays.sort(students,c1), why am i passing c1 now?

In order to meet the Comparable contract, you must have at least the compareTo method. You may have as many addition methods in your class as you would like.
It sorts the elements in the natural order based on the Comparable interface. So sort is calling compareTo between the elements to see in which order to place them.
Providing a Comparator to the sort method allows sort to order elements that either (a) don't implement Comparable or (b) where you want to order them in some other order than the "natural order" as defined by the class's Comparable implementation.
When you pass a Comparator to sort, it calls the Comparator's compare method rather than the elements' compareTo method (if implemented).
see What is an interface
see Comparator
see Comparable

You can define as many methods as you want in a Comparable, as long as you implement compareTo. This method can be used in many situations where the class is checked for comparation. For example, when inserting instances into an ordered TreeSet. compareTo provides a general ordering rule for all instances of the class.
Arrays.sort orders the array in the natural order of its elements. That is, using compareTo.
You can use Comparator to define a custom ordering rule. Like when you have a table you can sort by any of its columns. You could define a Comparator for each of its columns, and you could still have a class-inherent ordering rule (as in related to the reality the Class represents) defined in the class' compareTo.

Implementing Comparable obligates you to provide an implementation for compareTo().
All elements in the Object array passed to the Arrays.sort(Object[]) method must implement Comparable. If you want to use a Comparator instead, you have to use an Arrays.sort() method that takes a Comparator as a parameter. The method you use in your example above takes a Comparator as the second parameter - hence the need to provide c1 in the method call.

Related

Difference between Collections.sort(list) and Collections.sort(list,comparator)

What's the difference between:
public FlyingRabbit(){
list = new ArrayList<Sellable>();
}
public void sort(Comparator<Sellable> comp) {
Collections.sort(list, comp);
}
and:
public class CompareCategory implements Comparator<Sellable> {
#Override
public int compare(Sellable s1, Sellable s2) {
return (s1.getCategory()).compareTo(s2.getCategory());
}
}
I'm confused about why do I need to use the Comparator comp instead of using compare inside CompareCategory.
Collections.sort(List<T>) sorts the given List by the natural ordering of its elements. The natural ordering of an object can be defined by implementing the Comparable interface in the corresponding class. This interface provides a single method, compareTo, which returns
a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
On the other hand, Collections.sort(List<T>, Comparator<T>) orders the List's elements according to the given Comparator. Their natural ordering will be ignored for the sorting. This second method comes in hand when the List's elements already possess their natural ordering but we want to order them by a different criteria.
Here's a simple example with a Person class displaying name, last name and 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 o) {
//Defining Person's natural ordering by creating a comparator and comparing by last name and then name the current object and the given paramter
return Comparator.comparing(Person::getLastName).thenComparing(Person::getName).compare(this, o);
}
#Override
public String toString() {
return String.format("%s %s %d", name, lastName, age);
}
public static void main(String[] args) {
List<Person> list = new ArrayList<>(List.of(
new Person("Matt", "O'Brien", 30),
new Person("Conan", "O'Brien", 25),
new Person("Frank", "Johnson", 50)
));
//Original unordered list
System.out.println(list);
//List ordered by Person's natural ordering (last name and then name)
Collections.sort(list);
System.out.println(list);
//List ordered by custom criteria (age)
Collections.sort(list, Comparator.comparing(Person::getAge));
System.out.println(list);
}
}
If Sellable implements the interface Comparable you can use Collections.sort(list).
Otherwise you should create own Comparator and use Collections.sort(list, comparator). Because there must be a rule by which to compare elements of the Sellable type.
You don't need to provide a comparator when objects contained in the list implement Comparable interface.
Comparator & Comparator
That's how the purpose of this interface defined by the documention:
This interface imposes a total ordering on the objects of each class
that implements it. This ordering is referred to as the class's
natural ordering, and the class's compareTo method is referred to as
its natural comparison method.
On the other hand, comparator - is an object that is used to provide an ordering for collections of objects that don't have a natural ordering, i.e. there's no obvious specific way in which these object can be ordered, and their class doesn't implement Comparable.
Comparators are handy when objects are required to be ordered in differently depending on the situation. For instance, you have a class Student, and students can be sorted by their names, ids, grades, etc. And you can create a comparator for each of these cases either by creating a class implementing the interface Comparator and overrides method compare() (like in the code you've listed) or by making use of the static methods like Comparator.comparing() introduced with Java 8.
With that said, interfaces Comparator and Comparable serve the same purpose (to facilitate comparison of object), but have different use cases.
Caution: don't mix things together by creating a comparator inside the compareTo() method, as it's shown in another answer. It's a terrible idea. Why? Because such an implementation will create a new comparator for every invocation of this method. To sort a list of 10.000.000 elements, 10.000.000 * log(10.000.000) comparisons will be required, with each comparison compareTo() will be called and a new instance of comparator will be created. It'll have a negative impact on the application performance because creation of objects is costful, it requires memory allocation and then gives loads of work to the garbage collector.
Fluent sorting
In order to sort a list, you can use static methods sort() from the Collections utility class, that are part of the JDK since the very early version. And you could find lots code-snippets on the Internet, where Collection.sort() is being used.
With Java 8 method List#sort() was introduced in the List interface and you no longer need to resort to static methods from the Collections class. Instead you can directly invoke method sort() on the list, note that it always expects a comparator as an argument. If elements of the list implement Comparable you should pass null instead:
If the specified comparator is null then all elements in this list
must implement the Comparable interface and the elements' natural
ordering should be used.
myList.sort(null); // only if element of the implement Comparable

The default (natural) sorting order is: Country and then Week

Implement the class: WeeklyDataProper that extends the class WeeklyData.
Requirements:
The default (natural) sorting order is: Country and then Week
The class could be properly used in a HashSet collection. Two objects are considered equal if they have the same Country and Week attributes.
How can I do the first part of the question? by compareTo method?
Right now the result is:
int week, String country
I need :
String country, int week
First, HashSet does NOT maintain any order:
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time
The implementation of a SortedSet is TreeSet which may use a natural order for objects implementing Comparable interface (thus implementing compareTo method), or a custom comparator via constructor public TreeSet(Comparator<? super E> comparator)
So, class WeeklyDataProper may implement Comparable interface as follows (null checks omitted here):
public class WeeklyDataProper extends WeeklyData implements Comparable<WeeklyDataProper> {
// getters getCountry / getWeek implemented in the parent
// ...
#Override
public void int compareTo(WeeklyDataProper that) {
int result = this.getCountry().compareTo(that.getCountry());
if (result == 0) {
result = Integer.compare(this.getWeek(), that.getWeek());
}
return result;
}
}
However, it may be a bit redundant to implement a separate subclass just to sort the set of WeeklyData, therefore the sorted set of WeeklyData may be retrieved with the custom comparator:
SortedSet<WeeklyData> sorted = new TreeSet<>(
Comparator.<WeeklyData>comparing(WeeklyData::getCountry)
.thenComparingInt(WeeklyData::getWeek)
);

Comparable and Comaprator interfaces

It is generally said that comparator is used to have multiple sorting sequences of collection of objects while comparable is used to have single sorting sequence.
What is the use of comparator interface in java when it is possible to have multiple sorting sequences using comparable interface?
import java.util.*;
enum CompareValue {RollNo, Marks;}
class Student implements Comparable<Student> {
public int marks;
public int rollNo;
public static CompareValue comparator = CompareValue.RollNo;
Student (int marks, int rollNo) {
this.marks = marks;
this.rollNo = rollNo;
}
public int compareTo(Student s) {
switch (comparator) {
case RollNo:
return this.rollNo - s.rollNo;
case Marks:
return this.marks - s.marks;
}
return 0;
}
}
public class Test
{
public static void main (String[] args)
{
Student s1 = new Student(59, 103);
Student s2 = new Student(87, 102);
Student s3 = new Student(78, 101);
Student students[] = {s1, s2, s3};
Arrays.sort(students);
System.out.println("Student list sorted by rollno");
for (Student s:students) {
System.out.println(s.rollNo + " - " + s.marks);
}
Student.comparator = CompareValue.Marks;
System.out.println("Student list sorted by marks");
Arrays.sort(students);
for (Student s:students) {
System.out.println(s.rollNo + " - " + s.marks);
}
}
}
When your compareTo method has different behaviors based on the value of some static variable, you are basically introducing a global setting that controls the natural ordering of the Student class.
This could be confusing and counter intuitive to users of your class.
Besides, it makes the implementation of compareTo awkward, especially if you have more than two implementations, and each implementation depends on multiple instance variables.
Comparator is a much more suitable interface to supply multiple different comparisons for instances of the same class, each implementation having its own compare() logic.
When you have objects that do not implement comparable, but you would like to sort a collection consisting them, you would either have to extend them just to sort your collection or provide a comparator that compares them even though they are not comparable.
Or you might want to compare sort those objects in a different manner then their natural sort.
Imagine such an example.
String is an object that is comparable. Imagine you want to sort a collection of strings based on their hashCode instead of the string natural order. How would you do it without creating a comparator?
What you have shown there is indeed multiple sort orders using Comparable, but don't you think it's too much boiler plate code? Let's say if you have added a new field to the class called name, and now you want to sort by name. You'd have to:
add a new case to the enum
add a new case to the compareTo.
Another disadvantage of using the approach you showed is that it is not necessarily clear what this means:
Arrays.sort(student);
You would have to look through your code and check what value you have set the comparator.
Also, if I were using your class and I want to sort by something else, I would have to create a Comparator anyway, because I can't edit your class.
But if you use Comparator, you solve all of these problems:
Arrays.sort(students, Comparator.comparing(Student::getName));
Therefore, Comparable is only useful when there is one natural order, like dates and times for example.
If we look at the Comparable and Comparator interfaces and what they mean, everything will be clear.
Comparable:
This is an internal property of a JAVA class i.e. it assumes that whenever one uses the internal compareTo() method, one is using it for the specified object.
public int compareTo(T o);
Therefore, in implementation of this method we use this which is the current object and compare it to some other object of same type. These can be treated as defaults or use for natural ordering.
Like 1 comes before 2 and so on. This is the natural ordering.
Comparator:
This is property which actually is not tightly bound to the Java class itself. Comparators are used to actually provide a method to be used by some other services (like Collections.sort()) for achieving a particular goal.
int compare(T o1, T o2);
By this we mean, You can have multiple Comparators, providing different ways of achieving different goals wherein the actual service can pick any two objects and compare them.
This can be used to provide custom ordering, like using some equation we can come up with an ordering where f(1) actually comes after f(2) and so on. This equation will likely be achieving some order which solves a use-case.

Sorting an object java based on string member

I have an object of a custom type called Suffix which is defined as
class Suffix
{
int index;
String suff;
}
I create an Array of objects of type suffix
Suffix s[] = new Suffix[10];
I need to sort it according to the string suff data member. How can I do that? I am unable to understand most of the custom implementations available online.
eg :
If I have s[0].suff = "hats",s[1].suff = "ats", s[2].suff ="ts". Now I need to sort this array based on the suffix. ("ats",1) , ("hats",0) and ("ts",2) should be sorted order.
You can use Arrays.sort(..) if your object extends Comparable interface.
class Suffix implements Comparable<Suffix>
{
int index;
String suff;
#Override
public int compareTo(Suffix o) {
return this.suff.compareTo(o.suff);
}
}
You can use as below now
Suffix s[] = new Suffix[10];
Arrays.sort(s);
You got three possibilities:
Write your own sorting algorithm and compare the suff String there.
Implements the Comparable<> interface in your Suffix class, Override the comparteTo() method and use Arrays.sort(); which takes the array of Compareable objects as parameter.
Wirte a Comparator<> and use the Arrays.sort() method which takes the array and the Comparator.
The third way have one advantage. If you want to sort by index instead of suff param, you can pass another Comparator to the sort() method.
Suffix s[] = new Suffix[10];
Comparator comp = new Comparator<Suffix>(){
#Override
public int compare(Suffix arg0, Suffix arg1)
{
return arg0.suff.compareTo(arg1.suff);
}
};
Arrays.sort(s,comp);
You have nothing to change in your Suffix class. Hint: You can make an extra class with your Comparators as static fields.
Apart from using Comparable as #insert-username-here and #vinayknl said, The other one is using Comparator. Inside the method you want to sort add the following:
Comparator comparator = new Comparator<Suffix>() {
public int compare(Object o1, Object o2) {
Suffix s1 = (Suffix) o1;
Suffix s2 = (Suffix) o2;
return s1.getSuff().compareTo(s2.getSuff());
}
}
Array.sort(s, comparator);
Note: don't forget to add getter.
Check out the Comparable interface. This interface will allow your classes to be compared according to your own criteria.
Quick google search came up with this helpful page.

Need explanation of this program in java [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to understand, how the compareTo method is called in this program.
class Student implements Comparable {
String dept, name;
public Student(String dept, String name) {
this.dept = dept;
this.name = name;
}
public String getDepartment() {
return dept;
}
public String getName() {
return name;
}
public String toString() {
return "[dept=" + dept + ",name=" + name + "]";
}
public int compareTo(Object obj) {
Student emp = (Student) obj;
System.out.println("Compare to : " +dept.compareTo(emp.getDepartment()));
int deptComp = dept.compareTo(emp.getDepartment());
return ((deptComp == 0) ? name.compareTo(emp.getName()) : deptComp);
}
public boolean equals(Object obj) {
if (!(obj instanceof Student)) {
return false;
}
Student emp = (Student) obj;
boolean ii = dept.equals(emp.getDepartment()) && name.equals(emp.getName());
System.out.println("Boolean equal :" +ii);
return ii ;
}
public int hashCode() {
int i2 = 31 * dept.hashCode() + name.hashCode();
System.out.println("HashCode :" + i2);
return i2;
}
}
public class CompareClass {
public static void main(String args[]) {
Student st[] = { new Student("Finance", "A"),
new Student("Finance", "B"), new Student("Finance", "C"),
new Student("Engineering", "D"),
new Student("Engineering", "E"),
new Student("Engineering", "F"), new Student("Sales", "G"),
new Student("Sales", "H"), new Student("Support", "I"), };
Set set = new TreeSet(Arrays.asList(st));
System.out.println(Arrays.asList(st));
System.out.println(set);
}
}
Why is Arrays.asList(st) used?
What is use of equals() and hashcode()?
Why Arrays.asList(st) is used ?
Because the TreeSet constructor TreeSet(Collection c) accepts a Collection and not a String[] , hence you convert the String[] to a List which is a Collection using the method List asList(T... a). Note here , the array is same as varargs in this case.
What is use of equals() and hashcode() ?
Object class provides two methods hashcode() and equals() to represent the identity of an object.
You are using a TreeSet in your code . As per the documentation:
the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.
Hence in your case , implementing Comparable and overriding compareTo() is enough .
Suggested Reading:
Overriding equals and hashCode in Java.
Hashset vs Treeset
What is the difference between compare() and compareTo()?
.equals() is used because you are comparing two Objects.
There is a very good explanation of the Comparable interface in the Oracle documentation: http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html
In this code, Arrays.asList(st) is used basically because the author thought it was simpler to instantiate an Array in Java and convert it to a List than it is to create an ArrayList and call .add for each item. It's really not critical to what is going on, though. Another thing that happens on that same line is where the magic is.
Set set = new TreeSet(Arrays.asList(st));
This creates a TreeSet from the list. It is worth taking a look at this post: What is the difference between Set and List? briefly. In a Set, all elements are unique, so when you create a Set from a List that contains duplicates the Set constructor will throw the extra items away. How does it determine what elements are duplicates? It uses the methods of the Comparable interface. Similarly, a List is sorted but a Set is not so the implementation can choose to store the items in the Set in whatever order is most efficient. In the case of a TreeSet it handily explains how it does it right at the top of the Oracle documentation:
Note that the ordering maintained by a set (whether or not an explicit
comparator is provided) must be consistent with equals if it is to
correctly implement the Set interface. (See Comparable or Comparator
for a precise definition of consistent with equals.) This is so
because the Set interface is defined in terms of the equals operation,
but a TreeSet instance performs all element comparisons using its
compareTo (or compare) method, so two elements that are deemed equal
by this method are, from the standpoint of the set, equal. The
behavior of a set is well-defined even if its ordering is inconsistent
with equals; it just fails to obey the general contract of the Set
interface.
Some of the Java API was built around arrays and some of it was built around collections. asList is basically an adapter that lets your array be accessed like a collection.
Some data structures and algorithms operate on what's called the "hash" of a piece of data. This is done largely for performance reasons. In most cases the hash is a single number representing a particular object. You can see how this might be useful for sorting a collection quickly or checking equivalence.
equals exists of course to test if two objects represent the same thing.
I m trying to understand ,how the compareTo method is called in this program.
Because what you use here is a TreeSet, which implements SortedSet, and for which uniqueness is calculated by comparing elements using their natural ordering, and not equality.
Classes implementing Comparable of themselves, or a superclass of themselves, can be compared to one another. For classes which do not, you can supply a Comparator instead.
When you add an element to a SortedSet, the set will first compare it to elements already present in the set, and only add it if no comparison gives 0. See below for a demonstration.
See also Collections.sort().
1.Why Arrays.asList(st) is used ?
because this is Java 1.4 code. In Java 5, you'd use Arrays.asList(s1, s2, etc) (ie, a varargs method).
2.What is use of equals() and hashcode() ?
In this case, none.
Sample program (with generics this time) illustrating the difference between a SortedSet and a HashSet, using BigDecimal:
final BigDecimal one = BigDecimal.ONE;
final BigDecimal oneDotZero = new BigDecimal("1.0");
one.equals(oneDotZero); // false
one.compareTo(oneDotZero); // 0
// HashSet: uses .equals() and .hashCode();
final Set<BigDecimal> hashset = new HashSet<>();
hashset.add(one); hashset.add(oneDotZero);
hashset.size(); // 2
// TreeSet: uses Comparable
final Set<BigDecimal> treeset = new TreeSet<>();
treeset.add(one); treeset.add(oneDotZero);
treeset.size(); // 1
.equals and .hashcode are methods inherited from the Object class in java by every class.
When creating your own class you would usually override these two default implementations because the default Object function generally does not lead to the desired behavior.
They are there for good measure really, but as it is they are not being used.

Categories