0

i have to sort candiadates on the basics of both name and age .here the data

Arun 20 Bucky 22 Arun 25

and the output has to be

Arun 25 Arun 20 Bucky 22

here the coding

import java.util.Comparator;

public class Student implements Comparable<Student> {
    int id;
    String name;
    int age;

    public int compareTo(Student s1) {
          return this.age-s1.age;
       }

    //Constructor
    public Student(String name,int id,int age) {
        // TODO Auto-generated constructor stub
        this.name="";
        this.id=0;
        this.age=0;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

}

Here the main class

import java.util.ArrayList;

import java.util.Collections;

public class StudentList {

    public static void main(String args[]){
        ArrayList<Student> list=new ArrayList<Student>();
        Student s1= new Student(null, 0, 0);
        s1.setName("Andy");
        s1.setAge(25);
        s1.setId(1);
        Student s2=new Student(null, 0, 0);
        s2.setName("Brad");
        s2.setAge(22);
        s2.setId(2);
        Student s3=new Student(null, 0, 0);
        s3.setName("Andy");
        s3.setAge(30);
        s3.setId(3);
        list.add(s1);
        list.add(s2);
        list.add(s3);
        Collections.sort(list);

        for(Student a:list){
            System.out.println(a.getName()+""+a.getAge());
        }
    }
}
Kohei TAMURA
  • 4,970
  • 7
  • 25
  • 49
balan
  • 39
  • 3
  • 9

4 Answers4

4

You should change your compareTo() method:

public int compareTo(Student s1) {
     int nameCompare = this.name.compareTo(s1.name == null ? "" : s1.name);
     if(nameCompare == 0) return Integer.compare(this.age, s1.age);
     return nameCompare;
}
syntagma
  • 23,346
  • 16
  • 78
  • 134
  • Error:The method compare(String, String) is undefined for the type String help me to resolve this – balan May 29 '17 at 13:54
  • See my revised answer. – syntagma May 29 '17 at 13:55
  • The compareTo() shall not throw NullPointerException when name is null. The Student API clearly allows for name being null and the compareTo shall handle that. – Michal May 29 '17 at 19:34
  • @Michal Right, fixed it – syntagma May 29 '17 at 19:37
  • Now the compareTo() is not symmetric, i.e. it behaves differently based on whether s1.compareTo(s2) or s2.compareTo(s1) is called, provided one of s1 and s2 has name equal to null. – Michal May 29 '17 at 19:51
  • And how would you safely do such asymmetric call? – syntagma May 29 '17 at 19:53
  • In production code I would never implement comparison on my own, I would actually use Anton's answer and either make the Student object immutable and always fully initialized or enhance the comparator with Comparator.nullFirst / Comparator.nullsLast as in https://stackoverflow.com/questions/28499846/null-safe-mapping-comparator-using-default-implementations. – Michal May 29 '17 at 20:14
  • Just for the fun - for nulls last perhaps something like this.name==null ? s1.name!=null ? -1 : 0 : s1.name == null ? 1 : this.name.compareTo(s1.name) but please note I do not have a compiler at hand so this might or might not work. I would need to write quite a a few unit tests to prove the concept. – Michal May 29 '17 at 20:16
  • I probably would use methods from Java 8 as well but I wanted to point OP to the errors in his code. Answering my own question, I thinks there is no way to do two separate assymmetric calls as compareTo is unary method. – syntagma May 29 '17 at 20:18
  • Error:The method compare(String, String) is undefined for the type help me to resolve this @michal @ ΔλЛ – balan May 31 '17 at 06:55
  • I was writing from memory, corrected it later - you should use `String.compareTo(String)`. – syntagma May 31 '17 at 07:34
2

using the stream power of java8 you define 2 comparators (one by name and one by age)

List<Student> list = new ArrayList<>();
Comparator<Student> byName = (x, y) -> x.name.compareTo(y.name);
Comparator<Student> byAge = (l, r) -> Integer.compare(r.age, l.age);

list.add(new Student("Andy", 25, 1));
list.add(new Student("Brad", 22, 2));
list.add(new Student("Andy", 30, 3));


list.stream().sorted(byName.thenComparing(byAge)).forEach(System.out::println);

then stream -> sorted -> thenComparing (this is doing the trick is the first criteria returns that they are the same :))

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
0

Are you able to use Java-8? You can just use Comparator.comparing method. For example:

list.sort(Comparator.comparing(Student::getAge).thenComparing(Student::getName));

It will sort list of students based on age and then based on name; Or you can use Stream#sorted if you don't want to change the order of elements in the original list:

List<Student> sorted = list.stream().
    sorted(Comparator.comparing(Student::getAge).thenComparing(Student::getName).
    collect(Collectors.toList());

I hope this helps.

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
0

Arun 20 Bucky 22 Arun 25

and the output has to be

Arun 25 Arun 20 Bucky 22

You want to sort by name ASC then by age DESC

Implement Comparable in this way :

public int compareTo(Student other) {

   int nameComparison = String.compare(this.name, other.name)
   if (nameComparison != 0){           
       return nameComparison;
   }
      // DESC  order
   return -Integer.compare(age, other.age);
 }
davidxxx
  • 125,838
  • 23
  • 214
  • 215