Java Sort with Comparable - java

I have an ArrayList of Person objects. A Person has name, age and height. My goal is to sort this ArrayList<Person>. I have implemented Comparable<Person> and have defined compareTo() but when I try to sort it, it give me this error:
The method sort(Comparator) in the type ArrayList is not applicable for the argument ()"
The way I understand is that if you implement Comparable and then define compareTo everything else is magically done for you.
Can some one explain how to this works and why I am getting this error?

My guess is that your code looks like this:
ArrayList<Person> people = ...;
people.sort();
Look at the JavaDoc for ArrayList. Do you see a method public void sort() (with no parameters)? No - there is no such method.
That is the meaning of the error: The method sort(Comparator) in the type ArrayList is not applicable for the argument () -- There is a method sort(Comparator), but you have not supplied parameters that match it.
Assuming Person implements Comparable (and therefore has a compareTo() method), you can use Collections.sort(), which sorts arbitrary List<Comparable>
Collections.sort(people);
This is because Collections has a static method:
static <T extends Comparable<? super T>> void sort(List<T> list);
(it also has a sort(List<T> list, Comparator<T> comparator))
... or you can pass a comparator to List.sort(), which is quite easy with Java 8 lambdas:
people.sort((a,b) -> a.compareTo(b));
(Or, if you prefer the old style):
people.sort(new Comparator<String>() {
#Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
(Actually as of Java 8, this comparator is provided by the standard library, as Comparator.naturalOrder())
The point of comparators is that you can sort according to different criteria. For example:
people.sort((a,b) -> a.lastName().compareTo(b.lastName()));
people.sort((a,b) -> a.lastName().compareToIgnoreCase(b.lastName()));
people.sort((a,b) -> Integer.compare(a.age(),b.age()));
// etc.
... or using methods in Comparator:
people.sort(Comparator.comparing(Person::lastName));
people.sort(Comparator.comparing(Person::lastName)
.thenComparing(Person::firstName));

Either you use a structure which uses the Comparable interface to order its elements when you add a new element inside it :
TreeSet<Person> persons = new TreeSet<>();
Person personOne = ...
Person personTwo = ...
persons.add(personOne);
persons.add(personTwo);
Either you use a List and the Collections.sort(List<T> list) method which takes as argument the list you want to sort (there is an overload of this method but it is not relevant in your case):
List<Person> persons = new ArrayList<>();
Person personOne = ...
Person personTwo = ...
persons.add(personOne);
persons.add(personTwo);
Collections.sort(persons);
With the TreeSet, the elements are sorted as soon as added and with the List, the elements are not sorted when you add them. Only, the call to the Collections.sort() method sorts the list.

Related

How to sort the Object containing list in asc order

i want to get the data from list in asc order..
List<Region> region = (List<Region>) model.get("region");
if i am using Collection.sort(region);
then showing this,
The method sort(List) in the type Collections is not applicable for the arguments (List)
You need to define the class Region as Comparable or you need to pass an additional parameter of type Comparator to the sort method.
Without a Comparator the signature is
public static <T extends Comparable<? super T>> void sort(List<T> list)[1]
and the javadoc explicitly said that the class must implements Comparable:
Sorts 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).
in this case you need to modify your code as follow:
public class Region implements Comparable {
public int compareTo(Region o) {
// Add the logic to compare regions here.
}
...
}
The second version with a Comparator has the following signature:
public static <T> void sort(List<T> list, Comparator<? super T> c)
and all the elements must be comparable using the passed Comparator:
Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
In this case you need to change your code directly calling the sort method as follow:
Collections.sort(regionList, (Region r1, Region r2)-> {
// Add compare logic here
});
Note: there is an additional little mistake in your code the class to use is Collections (with an s) and not the interface Collection. I also changed the name of the list from region to regionList (eventually name it regions) because it is not only a single element but it is a list.
Custom comparator in a line for your code,
List<Region> region = (List<Region>) model.get("region");
Collections.sort(region, new Comparator<Region>() {
#Override
public int compare(Region a1, Region a2) {
return a1.getType().compareToIgnoreCase(a2.getType()); //You can alter this condition based on your condition to compare
}
});
You can leave the sorting to the database query.
As it seems the values should be unique, you could also have as model a SortedSet, implementing class: TreeSet.
i done with it...
Collections.sort(region, new Comparator<Region>() {
public int compare(Region obj1, Region obj2) {
return obj1.getStrRegion().compareTo(obj2.getStrRegion());
}
});

Java:Sorting an arraylist having linkedlist with the first element

Consider this arraylist with linkedlist objects
(are->1->3->7 , croco-> 4 ->1 , bat ->3->8).
Now I have to sort the arraylist in java in ascending order considering the first element of linkedlist contained in arraylist.
There is a method Collections.sort() but it is useful when objects are strings.
What to apply in this situation?
The final list should look something like this
(are->1->3->7 , bat ->3->8 , croco-> 4 ->1 )
Collections.sort(); has an overloaded method that takes a comparator as well. So you want something like this:
Collections.sort(lists, (o1, o2) ->
o1.get(0).compareTo(o2.get(0))
);
Or if you can use Java 8, there is a default sort method in List interface:
lists.sort(Comparator.comparing(o -> o.get(0)));
Without much context, I might be wrong. However, from my judgement if you're using your own objects which contain an identifier (are, croco and bat), and a linkedlist(numbers), then you can use the following solution.
Your class needs to implement the Comparable Interface
You need to override the compareTo() method
Collections.sort() should sort your objects in ascending order.
public class Example implements Comparable {
private String identifier;
private List<Integer> list;
// constructors
// getters
#Override
public int compareTo(Object other){
if(this.list.head() > other.list.head()) return 1;
if(this.list.head() < other.list.head()) return -1;
else return 0;
}
}

How to define comparator on SortedSet<> like TreeSet<>?

I want to make a lexical sorted list of strings, so i went with the basic SortedSet
1) Set<String> words = new SortedSet<String>(){}
and realized that SortedSet is an abstract class, in which I will have to implement the comapartor method. So i went and searched on google and found out that treeSet is better and i can use its predefined comparator method.
2) SortedSet<String> words = new TreeSet<String>(){}
When went to java docs i realized that TreeSet extends AbstractSet rather than SortedSet. Question 1 - Can anyone explain how the 2nd line is still working(like i am not generalizing the Set which i would normally do instead i am using two totally different Classes with no Parent child relation).
Question 2 - how to define comparator of SortedSet which will work as TreeSet. So here is the working code with TreeSet
SortedSet<String> words = new TreeSet<>();
Scanner scanner1 = new Scanner(System.in);
String s1 = scanner1.nextLine();
int a = scanner1.nextInt();
while(s1.length()>a){
words.add(s1.substring(0,a));
s1 = s1.substring(a);
}
Iterator itr = words.iterator();
while(itr!= null&&itr.hasNext()){
System.out.println(itr.next());
}
Normal Input
welcometojava
3
Expected Output
com
eto
jav
wel
Edit-1
For the answer of Question 2, i am expecting something like this
Set<String> words = new SortedSet<String>() {
#Override
public Comparator<? super String> comparator() {
return null;
}
......
I basically want to learn, how to make a basic comparator "like" in TreeSet while using SortedSet? I understand that if there is natural ordering i don't need to define a new comparator.
Answer 1:
TreeSet<T> implements the NavigableSet<T> interface, which extends SortedSet<T> who also extends Set<T>.
The interfaces themselves doesn't actually do the sorting, the concrete class does.
So:
Set<String> myStrings = new TreeSet<>();
// Add a bunch of strings
// ...
for (String s : myStrings) {
System.out.println(s);
}
You would still have them in sorted order.
Answer 2:
Firstly, for classes that already implement Comparable<T>, you can omit the Comparator for the TreeSet, as "Natural Ordering" is meant by using the Comparable<T>'s compareTo method.
Otherwise you can supply a Comparator instance to as the TreeSet constructor's first argument:
Set<String> myStrings = new TreeSet<>(new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
// Define comparing logic here
return o1.compareTo(o2);
}
});
or use Java 8 Lambdas:
Set<String> myStrings = new TreeSet<>((o1, o2) -> o1.compareTo(o2));
To answer your question,
TreeSet also implements NavigableSet which extends SortedSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable
public interface NavigableSet<E> extends SortedSet<E>
By default sort will be done based on natural ordering and the basic primitives wrappers (Integer, Long, ...) implements Comparable interface, so no need to implement the Comparable if the collection holds wrappers of Primitives and natural ordering is expected
But your custom class should implement Comparable if it should be ordered in TreeSet else ClassCastException will be thrown once you add the second element
TreeSet implements NavigableSet, which in turn extends SortedSet, which is why line 2) works. See TreeSet Java doc.
For the second part, try this:
SortedSet<String> ts = new TreeSet<String>(new TSComparator());
class TSComparator implements Comparator<String>{
#Override
public int compare(String str1, String str2) {
return str1.compareTo(str2);
}
}
SortedSet<T> is not an abstract class, it is an interface.
TreeSet<T> does implement SortedSet<T>, but not directly: the chain of inheritance goes as follows:
Set<T> - SortedSet<T> - NavigableSet<T>
That is why the assignment SortedSet<String> words = new TreeSet<String>() works: TreeSet<T> is a NavigableSet<T>, and NavigableSet<T> is a SortedSet<T>, so the assignment is legal.
When you do not supply an explicit comparator, TreeSet<T>'s uses natural ordering supplied by T's implementation of Comparable<T>.

How will sort method do a sort, on a list that contains objects of type Foo?

How will a LinkedList of type :
LinkedList<FooClass> list = new LinkedList<FooClass>();
// FooClass extends Comparable
list.add(foo_obj_1);
list.add(foo_obj_2);
list.add(foo_obj_3);
list.add(foo_obj_4);
be sorted by :
Collection.sort(list);
What effect will sort method have on list that contains a list of objects.On what basis will the list be sorted ?
If you make you an object comparable, then you override the compareTo method. You can then write your own custom criteria based on what fields you want to compare. A sort can then be performed as usual.
class Author implements Comparable<Author>{
String firstName;
String lastName;
#Override
public int compareTo(Author other){
int last = this.lastName.compareTo(other.lastName);
return last == 0 ? this.firstName.compareTo(other.firstName) : last;
}
}
If your object does not implement Comparable then you will not be able to perform any of the various sort implementations.
Check out the API of Collections#sort(List<T>). It will only compile if T extends Comparable.
If Foo does not extend Comparable, your code will not compile.
If it does, the list will be sorted by Foo's natural ordering, as explained here.

Sorting a list of non-comparable elements

Today I was asked this interview question:
If I have a Person class with name, age and salary fields, and I put 100 new instances of this Person in an ArrayList, and then do Collections.sort(list), then on what parameter will the list be sorted?
I understand that I need to have the Person class implement Comparable and then override compareTo, but if I don't do that, what will happen?
It wouldn't compile: the 1-argument version of Collections.sort expects a list of Comparables. Specifically, a List<T> where T implements Comparable<? super T>.
Yes you can sort a collection without making the elements implement the Comparable Interface, you do this
List<YourType> theList = new ArrayList<>();
Collections.sort(theList, new Comparator<YourType>(){
public int compare(YourType obj1, YourType obj2) {
// this method should return < 0, 0 or > 0
// whether obj1 is less than, equal to
// or greather than obj2
return 0;
}
});
/edit,
if you use Collections.sort(List) then it will compile only if the list is generic and it's elements implements Comparable. And if so, then the implementation of the compareTo(Obj) on each element is what will determine the ordering in the list after the sort(List) method is called
as the Collections API states:
public static <T extends Comparable<? super T>> void sort(List<T> list)
Sorts 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).
If the Person class does not implement Comparable<Person>, then (as the compiler will inform you):
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<Person>). The inferred type Person is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>.
(If you happened to have a Comparator<Person> lying around, Collections.sort(myList, myComparator) would sort it by the ordering specified by the comparator.)

Categories