10

I am new to Java 8. I just want to sort by the name. But the condition is: if there are duplicate names then it should be sorted according to age.

For example my input is

tarun  28
arun   29
varun  12
arun   22

and the output should be

arun   22
arun   29
tarun  28
varun  12

But I get something like

varun  12
arun   22
tarun  28
arun   29

Means it's sorted either only by ages or names.

This is the code which is implemented:

POJO class:

class Person {

    String fname;

    int age;

    public Person() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFname() {
        return fname;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public Person(String fname,  int age) {
        this.fname = fname;

        this.age = age;
    }

    @Override
    public String toString() {
        return fname  + age;
    }
}

Test class:

public class Test {

    public static void main(String[] args) {
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("tarun", 28));
        persons.add(new Person("arun", 29));
        persons.add(new Person("varun", 12));
        persons.add(new Person("arun", 22));

        Collections.sort(persons, new Comparator<Person>() {

            @Override
            public int compare(Person t, Person t1) {
                return t.getAge() - t1.getAge();
            }
        });
        System.out.println(persons);

    }
}
Marvin
  • 13,325
  • 3
  • 51
  • 57
Pavan Kumar
  • 412
  • 1
  • 6
  • 15

8 Answers8

18

Currently you are a) only comparing by one attribute and b) not really making use of Java 8's new features.

With Java 8 you can use method references and chained comparators, like this:

Collections.sort(persons, Comparator.comparing(Person::getFname)
    .thenComparingInt(Person::getAge));

This will compare two Person instances first by their fname and - if that is equal - by their age (with a slight optimization to thenComparingInt to avoid boxing).

Marvin
  • 13,325
  • 3
  • 51
  • 57
4

You need to compare for names first. If the names are the same, then and only then the result depends on comparing the age

public static void main(String[] args) {
    List<Person> persons = new ArrayList<>();
    persons.add(new Person("tarun", 28));
    persons.add(new Person("arun", 29));
    persons.add(new Person("varun", 12));
    persons.add(new Person("arun", 22));

    Collections.sort(persons, new Comparator<Person>() {

        public int compare(Person t, Person t1) {
            int comp = t.getFname().compareTo(t1.getFname());
            if (comp != 0) {    // names are different
                return comp;
            }
            return t.getAge() - t1.getAge();
        }
    });
    System.out.println(persons);

}}

if you want to change from ascending to descending, just change the sign. e.g.

 return -comp;

or swap the person

name

 int comp = t1.getFname().compareTo(t.getFname());

age

 return t1.getAge() - t.getAge();
stefan bachert
  • 9,413
  • 4
  • 33
  • 40
3

You are on the right path, but your compare method is incomplete.

Since compare is called to decide which item in each pair is to go before the other, it must include all comparison logic, not only the tie-breaking one. Your code sorts on the age alone, ignoring the name completely.

The logic should go like this:

  • Compare names using t.getFname().compareTo(t1.getFname())
  • If names are not the same, return the result of comparison
  • Otherwise, return the result of comparing ages.

Proper way of comparing integers is with the static Integer.compare method, i.e. Integer.compare(t.getAge(), t1.getAge()).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Your Comparator is only sorting by age, not by name.

You could try it like that:

new Comparator<Person>() {
    @Override
    public int compare(Person t, Person t1) {
        int ret = t.getFname().compareTo(t1.getFname());
        if (ret == 0) {
           ret = Integer.compare(t.getAge(), t1.getAge()); 
        }
        return ret;
    }
}

You could also think about implementing Comparable<Person> in the Person class itself:

class Person implements Comparable<Person> {
    @Override
    public int compareTo(Person p) {
        int ret = fname.compareTo(p.fname);
        if (ret == 0) {
           ret = Integer.compare(age, p.getAge()); 
        }
        return ret;

    }
}
Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
Dorian Gray
  • 2,913
  • 1
  • 9
  • 25
1

You can use Comparator.comparing method, introduced in Java 8, returns a Comparator object that will use the specified field as the sort key.

final Function<Person, Integer> byAge = person -> person.getAge();   
final Function<Person, String> byTheirName = person -> person.getFname();
System.out.println("Sorted in ascending order by age and name: ");
        List<Person> sortedlist =   people.stream()
            .sorted(Comparator.comparing(byAge).thenComparing(byTheirName))
            .collect(Collectors.toList());
        sortedlist.forEach(System.out::println);

We first created two lambda expressions, one to return the age of a given person and the other to return that person’s name. We then combined these two lambda expressions in the call to the sorted() method to compare on both properties. The comparing() method created and returned a Comparator to compare based on age. On the returned Comparator we invoked the thenComparing() method to create a composite comparator that compares based on both age and name

Vishwa Ratna
  • 5,567
  • 5
  • 33
  • 55
0

This is simple one liner comparison using ternary operator for sorting the objects. No need to write so many if/else block.

Collections.sort(persons, new Comparator<Person>() {

    @Override
    public int compare(Person t1, Person t2) {

        return t1.getFname().equals(t2.getFname()) ? t1.getAge()-t2.getAge() : t1.getFname().compareTo(t2.getFname());

    }
});
nagendra547
  • 5,672
  • 3
  • 29
  • 43
0

// Sort Without using Comparator

import java.util.ArrayList; import java.util.List;

public class SortByNameThenAge {

static class Student {
    String name;
    int age;

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

}

public static void main(String[] args) {
    List<Student> olist = new ArrayList<>();
    olist.add(new Student("Sam", 26));
    olist.add(new Student("Sam", 22));
    olist.add(new Student("Abc", 25));
    olist.add(new Student("Abc", 22));
    olist.add(new Student("Abc", 23));
    olist.add(new Student("Sam", 24));
    olist.add(new Student("Sam2", 21));
    olist.add(new Student("Sam2", 19));
    // Order By name
    for (int i = 0; i < olist.size(); i++) {
        for (int j = olist.size() - 1; j > i; j--) {
            if (olist.get(i).name.compareTo(olist.get(j).name) > 0) {
                Student temp = olist.get(i);
                olist.set(i, olist.get(j));
                olist.set(j, temp);
            }
        }
    }

    for (Student s : olist) {
        System.out.println(s.name + " : " + s.age);
    }

    // Order by name then age
    for (int i = 0; i < olist.size(); i++) {
        for (int j = i+1; j < olist.size(); j++) {
            if (olist.get(i).name.compareTo(olist.get(j).name) == 0) {
                if (olist.get(i).age > olist.get(i + 1).age) {
                    Student temp = olist.get(i);
                    olist.set(i, olist.get(i + 1));
                    olist.set(i + 1, temp);
                }
            }
        }
    }
    System.out.println("\nSorting by age keeping name as it is");

    for (Student s : olist) {
        System.out.println(s.name + " : " + s.age);
    }
}

}

0

You can simply use the stream sorted method with static reference of getName and getAge methods.

List<Person> list=new ArrayList<Person>();
list.stream().sorted(Comparator.comparing(Person::getName).thenComparing(Person::getAge)).collect(Collectors.toList()).forEach(System.out::println);
Harleen
  • 773
  • 3
  • 15
  • 25
garima garg
  • 308
  • 1
  • 8
  • @user:10852356/garmia garg How a List of Person object can be used in comparing method? There will be a compilation error, either write Person::getName & Person::getAge instead of Employee::getName & Employee::getAge or create a List list = new ArrayList(); The correct use would be : List list=new ArrayList(); list.stream().sorted(Comparator.comparing(Person::getName).thenComparing(Person::getAge)).collect(Collectors.toList()).forEach(System.out::println); – Harleen May 24 '23 at 15:03