I want to sort a TreeMap by ascending order wrt "Student.name". I don't want to create a new ArrayList. Is there any way to do this?
Map studentMap = new TreeMap();
studentMap.put(id, student); //id is double
public class Student{
String name;
int number;
....
}
You can do this in two ways:
Since you can't pass a value-based comparator to TreeMap, you can do this:
TreeMap sort by value
Making Student implement Comparable interface
public class Student implements Comparable<Student> {
#Override
public int compareTo(Student o) {
return this.getName().compareTo(o.getName());
}
}
In first case, you need to call the mentioned method on your collection. In the second one, just add students to your map.
You can use a custom comparator for that while creating the TreeMap.
Map studentMap = new TreeMap(new Comparator<Student>() {
#Override
public int compare(Student o1, Student o2) {
// Your logic to sort it based on Student name goes here
return 0;
}
});
if you are using TreeMap then the record will be already sorted .You need to implement the Comparable interface in Student class and have to override the compareTo method
Student implements Comparable {
// override compareTo wrt name
#Override
public int compareTo(Student otherStudent) {
return name.compareTo(otherStudent.name);
}
}
TreeMap is sorting its entries according to keys, not values. You cannot provide a Comparator<Student> since you have Double keys.
If you really need a map from Double to Student you cannot sort it in the way you want.
If not consider using a TreeSet<Student> with a Comparator<Student> or Comparable<Student>.
Related
This question already has answers here:
Sorting an ArrayList of objects using a custom sorting order
(12 answers)
Closed 6 years ago.
If I have a simple list of Strings:
List<String> stringList = new ArrayList<String>();
I can sort it with:
Collections.sort(stringList);
But suppose I have a Person class:
public class Person
{
private String name;
private Integer age;
private String country;
}
And a list of it:
List<Person> personList = new ArrayList<Person>();
And I want to sort it sometimes by name, sometimes by age, sometimes by country.
What is the easiest way to accomplish that?
I know that I can implement the Comparable interface, but that seems to limit me to sort it by one specific property.
Collections.sort can be called with a custom comparator. And that comparator can be implemented to allow sorting in different sort orders. Here's an example (for your Person model - with age as an Integer):
public class FlexiblePersonComparator implements Comparator<Person> {
public enum Order {Name, Age, Country}
private Order sortingBy = Name;
#Override
public int compare(Person person1, Person person2) {
switch(sortingBy) {
case Name: return person1.name.compareTo(person2.name);
case Age: return person1.age.compareTo(person2.age);
case Country: return person1.country.compareTo(person2.country);
}
throw new RuntimeException("Practically unreachable code, can't be thrown");
}
public void setSortingBy(Order sortBy) {
this.sortingBy = sortingBy;
}
}
And you use it like that (assuming persons is a field):
public void sortPersonsBy(FlexiblePersonComparator.Order sortingBy) {
List<Person> persons = this.persons; // useless line, just for clarification
FlexiblePersonComparator comparator = new FlexiblePersonComparator();
comparator.setSortingBy(sortingBy);
Collections.sort(persons, comparator); // now we have a sorted list
}
Implement the Comparator interface (once for each different sort order) and use the Collections.sort() method that takes a Comparator as additional parameter.
Thanks to the responders. For the benefit of others, I'd like to include a complete example.
The solution is the create the following additional classes:
public class NameComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getName().compareTo(o2.getName());
}
}
public class AgeComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getAge().compareTo(o2.getAge());
}
}
public class CountryComparator implements Comparator<Person>
{
public int compare(Person o1, Person o2)
{
return o1.getCountry().compareTo(o2.getCountry());
}
}
The list can then be sorted like this:
Collections.sort(personList, new NameComparator());
Collections.sort(personList, new AgeComparator());
Collections.sort(personList, new CountryComparator());
The Java 8 way of doing this is to use List.sort as follows:
personList.sort(Comparator.comparing(Person::getName));
To quote Stuart Marks in his answer over here.
This is the big advantage of the List.sort(cmp) extension method over Collections.sort(list, cmp). It might seem that this is merely a small syntactic advantage being able to write myList.sort(cmp) instead of Collections.sort(myList, cmp). The difference is that myList.sort(cmp), being an interface extension method, can be overridden by the specific List implementation. For example, ArrayList.sort(cmp) sorts the list in-place using Arrays.sort() whereas the default implementation implements the old copyout-sort-copyback technique.
You could also use the BeanComparator from apache commons beanutils, like this:
Collections.sort(personList, new BeanComparator("name"));
Implement 3 different types of Comparator.
you can add the comparator to the sort command. The comparator you define, will sort the elements by name, age, or what ever.
Collections.sort(list, new Comparator() {
public int compare(Object arg0, Object arg1) {
if (!(arg0 instanceof Person)) {
return -1;
}
if (!(arg1 instanceof Person)) {
return -1;
}
Person pers0 = (Person)arg0;
Person pers1 = (Person)arg1;
// COMPARE NOW WHAT YOU WANT
// Thanks to Steve Kuo for your comment!
return pers0.getAge() - pers1.getAge();
}
});
The Collections.sort method can be invoked with a second argument which is the comparator to use.
Create 3 comparators and use the one you want when appropriate.
Collections.sort(list , new Comparator() {
public int compare(Object o1, Object o2) {
...
}
});
Using lambdaj ( http://code.google.com/p/lambdaj/ ) you can achieve what you're asking in the following way:
sort(personList, on(Person.class).getName());
sort(personList, on(Person.class).getAge());
sort(personList, on(Person.class).getCountry());
I asked a very similar question (about searching rather than sorting), perhaps there is some useful information (I ended up using an enum that implements Comparator so I pass the enum value as a comparator selector).
I'm learning Java and I saw the code below on Youtube. I was just wondering how this part of the code works.
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};
Could someoen please explain it to me? Thanks in advance for any help!
import java.util.*;
public class EmpSort {
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};
// Employee database
static final Collection<Employee> employees = ... ;
public static void main(String[] args) {
List<Employee> e = new ArrayList<Employee>(employees);
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
}
}
The SENIORITY_ORDER Comparator (used for comparing Employees in the sort) is an Anonymous Class. The linked Java Tutorial reads (in part)
Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.
Well as we all konw . the Comparator is the rule that how to compare tow Object.
you can come into this Method : Collections.sort(e, SENIORITY_ORDER);
and you will see the answer you want
public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c); //this is your rule to compare
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set(a[j]);
}
}
if your Object not implements comparable so you must have a comparetor
or it's will be a wrong. The Collections.sort will to call the compare() Method.
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};
The statement static final Comparator<Employee> SENIORITY_ORDER = new Comparator<Employee>(){}
is creating a reference of the Comparator<Employee> interface that points to an instance of an Anonymous Inner Class which implements the Comparator<Employee> interface. Hence, you are overrding the compare() method of Comparator Interface inside your anonymous class.
Inside the compare() method you are comparing the hireDate attribute of two Employee objects using the compareTo() method of the Comparable interface in java. This method, compareTo(), compares the two attributes i.e, e1.hireDate and e2.hireDate, lexicographically and returns either a positive integer, a negative integer or zero, depending on whether e2.hireDate is greater than, less than or equal to e1.hireDate.
(HOPE YOU ARE ALREADY AWARE WITH THE CONCEPTS OF COMPARATOR INTERFACE AND NESTED CLASSES IN JAVA)
i have a question, i want to sort a list.
I want to write a compareTo mthod, but I want to asign to variable to the compareTo method, like this
public int compareTo(Object object, LinkedList<Integer> list) {
...
}
is it possible to do this?
Thank you for your help
No, You cannot change the method signature of an abstract method in Comparable interface. While implementing Comparable interface, you need to implement
int compareTo(T o)
Isn't it what cooperators are for?
List<Integer> list = new ArrayList<Integer>();
Collections.sort(list, new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
You can use List implementing Comparable interface in the same class:
class A implements Comparable<Integer> {
List<Integer> list = new ArrayList<Integer>();
#Override
public int compareTo(Integer o) {
return compareTo(o, list);
}
private int compareTo(Integer o, List<Integer> list) {
return ...; // Your comparison here
}
}
You will have to use the Comparable interface if you want to use the build in sort functions.
So the the answer would be no. If you want to have access to an extra objecct have that as a variable in the class.
I don't want to implement Comparable or Comparator in POJO. And i know how to sort using TreeSet.
This is my Person class. I need to sort based on name. Please help me on this
class Person{
String name;
}
How i can do like this.
Set<Person> s = new LinkedHashSet<Person>(new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
});
A LinkedHashSet keeps insertion order. To sort you need to use a TreeSet, it has a the correct constructor
TreeSet(Comparator<? super E> comparator)
Is it required to implement comparator or comparable if i want to invoke binarySearch() method to perform Search operation?I
I am facing exception when try to invoke binarySearch() method.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
class Student implements{
private int id;
private String name;
public Student(int id, String name){
this.id = id;
this.name = name;
}
public Student() {
// TODO Auto-generated constructor stub
}
public int getId(){
return id;
}
public String getName(){
return name;
}
}
public class CollectionSearchDemo {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student(3, "ouier"));
list.add(new Student(2, "fdgds"));
list.add(new Student(7, "kiluf"));
list.add(new Student(1, "6trfd"));
list.add(new Student(8, "hjgas"));
list.add(new Student(5, "ewwew"));
Collections.sort(list, new Comparator<Student>() {
#Override
public int compare(Student arg0, Student arg1) {
return arg0.getId() - arg1.getId();
}
});
Iterator iterator = list.iterator();
while(iterator.hasNext()){
Student student = (Student) iterator.next();
System.out.print(student.getId()+":"+student.getName()+" ");
}
System.out.println("I want to do searching ");
System.out.println("\n2 is at:"+Collections.binarySearch(list, 2, new Student()));
// facing exception when i invoke binarySearch method.
}
}
An exception occurs when i try to search "new Student()" or "CollectionSearchDemo" as an argument.
I have no idea what should i pass as an argument in binraySearch method.
Please help me
There are two ways to use Collections.binarySearch. The first with just a list of elements and a key, but these elements must implement Comparable. The second way with the key and a comparator. If you don't want Student to implement Comparable, you have to use this one.
So you have to write something like :
Collections.binarySearch(list, studentToBeFound, comparator);
with studentToBeFound being a Student instance and the comparator being a Comparator<Student> like the one you used in Collection.sort().
Just reuse your previous Comparator that compare with Id:
private static final class StudentComparator implements Comparator<Student> {
#Override
public int compare(Student arg0, Student arg1) {
return arg0.getId() - arg1.getId();
}
}
Then, if you want to find the student with Id equal to 2:
Student studentToBeFound = new Student(2, "dummy string");
And use them with binarySearch:
int indexInList = Collections.binarySearch(list, studentToBeFound, new StudentComparator());
The short answer is yes - the binary search does not know whether the Student you are searching for is 'bigger' or 'smaller' then each in the list and therefore cannot search.
You want to implement comparable on the Student using the code you already have in the comparator:
public class Student implements Comparable<Student> {
//stuff
#Override
public int compareTo(Student o) {
return getId() - o.getId();
}
}
Then your code with look something like this:
final Set<Student> set = new TreeSet<Student>();
//add students etc...
final Student found = Collections.binarySearch(set, studentToLookFor);
A list cannot be sorted if we do not know how it is to be ordered. The binary search algorithm requires that the list be sorted and it uses the ordering of the list to search the list bu cutting the search field in half with each iteration. But the notion of whether Student x is in the first half of the list or the second half of the list requires that we know how this list is sorted.
Option 1: public class Student implements Comparable<Student>
Option 2: Write a Comparator class for Students.
public class StudentComparator implements Comparator<Student>
The third parameter of binarySearch method must be a Comparator, the exception is thrown because your class Student doesn't implement Comparator interface.
binarySearch(List list, Object key, Comparator c)
Read here: http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html
The parameter c must be an instance of a class that implements Comparator.
Binary Search needs a sorted list.
This kind of searching is based in partitions:
Taking the middle element and comparing it to the reference.
The binary search continues in the first half of the collection if the comparation states that your reference is "lower" or, it continues in the second half if it is "higher".
When the comparation returns 0, the element was found.
With this in mind, it is actually a requirement that the list is sorted. You can do it in different ways:
Sorting it with the aid of a Comparator and then invoking binarySerarch
Sorting a collection of elements that implement the Comparable interface and then invoking binarySearch
Leaving the sorting to the binarySearch method if you provide the required Comparator.