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);
}
}
There are multiple ways to sort a list in Java 8, for example, you can get a stream from the List and then use the sorted() method of Stream class to sort a list like ArrayList, LinkedList, or Vector and then convert back it to List. Alternatively, you can use the Collections. sort() method to sort the list.
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).
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
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();
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:
t.getFname().compareTo(t1.getFname())
Proper way of comparing integers is with the static Integer.compare
method, i.e. Integer.compare(t.getAge(), t1.getAge())
.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With