Collections.sort with multiple fields
Do you see anything wrong with the code?
Yes. Why are you adding the three fields together before you compare them?
I would probably do something like this: (assuming the fields are in the order you wish to sort them in)
@Override public int compare(final Report record1, final Report record2) {
int c;
c = record1.getReportKey().compareTo(record2.getReportKey());
if (c == 0)
c = record1.getStudentNumber().compareTo(record2.getStudentNumber());
if (c == 0)
c = record1.getSchool().compareTo(record2.getSchool());
return c;
}
How to sort by two fields in Java?
You can use Collections.sort
as follows:
private static void order(List<Person> persons) {
Collections.sort(persons, new Comparator() {
public int compare(Object o1, Object o2) {
String x1 = ((Person) o1).getName();
String x2 = ((Person) o2).getName();
int sComp = x1.compareTo(x2);
if (sComp != 0) {
return sComp;
}
Integer x1 = ((Person) o1).getAge();
Integer x2 = ((Person) o2).getAge();
return x1.compareTo(x2);
}});
}
List<Persons>
is now sorted by name, then by age.
String.compareTo
"Compares two strings lexicographically" - from the docs.
Collections.sort
is a static method in the native Collections library. It does the actual sorting, you just need to provide a Comparator which defines how two elements in your list should be compared: this is achieved by providing your own implementation of the compare
method.
Collections.sort for multiple conditions
You can use Java Streams. This is also used when using Collection.sort()
:
myList.sort(Comparator.comparing(MyObject::getAttributeX)
.thenComparing(i -> i.getSomething().getSubValue())
.thenComparing((a, b) -> a.getInt() - b.getInt()));
If you are using a lower version than Java 8 you have to implement the sort logic yourself in a Comparator
or use an external library:
Collections.sort(myList, new Comparator<MyObject>() {
@Override
public int compare(MyObject a, MyObject b) {
int cmp0 = a.getAttributeX().compareTo(b.getAttributeX());
if (cmp0 != 0) {
return cmp0;
}
int cmp1 = a.getSomething().getSubValue().compareTo(b.getSomething().getSubValue());
if (cmp1 != 0) {
return cmp1;
}
return a.getInt() - b.getInt();
}
});
How to sort a list by multiple fields in different orders (asc/desc) in Java?
Comparator.reversed() for descending order
Comparator<Element> compar = Comparator.comparing(Element::getA)
.thenComparing(Comparator.comparing(Element::getB).reversed())
.thenComparing(Element::getC);
yourArrayList.sort(compar);
In addition to the reversed
method I am exploiting the fact that thenComparing()
is overloaded: one thenComparing()
takes a Comparator
as argument, which we need for reversing, the other just takes a method reference (or lambda) as argument (a Function
in the declaration of thenComparing()
).
If either a
, b
or c
is a primitive int
, long
or double
remember to use comparingInt()
, comparingLong()
, comparingDouble()
, thenComparingInt()
, etc.
Sort a List of objects by multiple fields
Your Comparator would look like this:
public class GraduationCeremonyComparator implements Comparator<GraduationCeremony> {
public int compare(GraduationCeremony o1, GraduationCeremony o2) {
int value1 = o1.campus.compareTo(o2.campus);
if (value1 == 0) {
int value2 = o1.faculty.compareTo(o2.faculty);
if (value2 == 0) {
return o1.building.compareTo(o2.building);
} else {
return value2;
}
}
return value1;
}
}
Basically it continues comparing each successive attribute of your class whenever the compared attributes so far are equal (== 0
).
Sort a list of Java objects by multiple fields and group by a particular field
The solution you have posted seems to be too complex for this problem. Given below is a clean approach for solving it:
- Sort employees using the comparators defined in the class,
Solution
. - Group employees by group ID with the sum of salary as the grouping function. In other words, create a
Map
in whichgroupId
will be the key and the sum of salaries pertaining to thegroupId
will be the value. Iterate the sorted entry set of
map
created in step#2 and put the records corresponding to each entry into the result list.Given below is the code implementing the above-mentioned algorithm:
// Sort employees using the comparators defined in the class, Solution
new Solution().sortEmployees(empList);
// Group employees by group ID with the sum of salary as the grouping function
Map<String, Integer> map = new HashMap<>();
for (Employee e : empList) {
String grp = e.getGroupId();
if (grp == null) {
grp = "null";
}
Integer salary = map.get(grp);
map.put(grp, salary == null ? e.getSalary() : e.getSalary() + salary);
}
// Result list
List<Employee> result = new ArrayList<>();
// Iterate the sorted entry set of `map` and put the records corresponding to
// an entry into the result list
for (Entry<String, Integer> entry : entriesSortedByValues(map)) {
String grp = entry.getKey();
int i;
// Find the starting index of `grp` in empList
if ("null".equals(grp)) {// Special handling for employees with `null` group
// Find the index in `empList` where employees with the group as `null` starts
for (i = 0; i < empList.size() && empList.get(i).getGroupId() != null; i++)
;
// Add elements before a different group is encountered
for (int j = i; j < empList.size() && empList.get(j).getGroupId() == null; j++) {
result.add(empList.get(j));
}
} else {
// Find the index in `empList` where employees with the group as `grp` starts
for (i = 0; i < empList.size() && !grp.equals(empList.get(i).getGroupId()); i++)
;
// Add elements before a different group is encountered
for (int j = i; j < empList.size() && grp.equals(empList.get(j).getGroupId()); j++) {
result.add(empList.get(j));
}
}
}Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
class Employee {
String empId;
String groupId;
int salary;
public Employee(String empId, String groupId, int salary) {
this.empId = empId;
this.groupId = groupId;
this.salary = salary;
}
public String getEmpId() {
return empId;
}
public String getGroupId() {
return groupId;
}
public int getSalary() {
return salary;
}
@Override
public boolean equals(Object obj) {
Employee other = (Employee) obj;
return Objects.equals(empId, other.empId) && Objects.equals(groupId, other.groupId)
&& Objects.equals(salary, other.salary);
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", groupId=" + groupId + ", salary=" + salary + "]";
}
}
class EmployeeChainedComparator implements Comparator<Employee> {
private List<Comparator<Employee>> listComparators;
public EmployeeChainedComparator(Comparator<Employee>... comparators) {
this.listComparators = Arrays.asList(comparators);
}
@Override
public int compare(Employee o1, Employee o2) {
for (Comparator<Employee> comparator : listComparators) {
int result = comparator.compare(o1, o2);
if (result != 0)
return result;
}
return 0;
}
}
class EmployeeGroupComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
if (o2.getGroupId() == null)
return (o1.getGroupId() == null) ? 0 : -1;
if (o1.getGroupId() == null)
return 1;
return o1.getGroupId().compareTo(o2.getGroupId());
}
}
class EmployeeSalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
return o2.getSalary() - o1.getSalary();
}
}
class Solution {
void sortEmployees(List<Employee> employees) {
Collections.sort(employees,
new EmployeeChainedComparator(new EmployeeGroupComparator(), new EmployeeSalaryComparator()));
}
}
public class Q62447064 {
public static void main(String[] args) {
List<Employee> empList = new ArrayList<>(List.of(new Employee("emp1", "grp1", 500),
new Employee("emp2", null, 600), new Employee("emp3", null, 700), new Employee("emp4", "grp2", 800),
new Employee("emp5", "grp1", 700), new Employee("emp6", "grp2", 1000),
new Employee("emp7", "grp1", 800), new Employee("emp8", null, 1000),
new Employee("emp9", "grp2", 600)));
// Sort employees using the comparators defined in the class, Solution
new Solution().sortEmployees(empList);
// Group employees by group ID with the sum of salary as the grouping function
Map<String, Integer> map = new HashMap<>();
for (Employee e : empList) {
String grp = e.getGroupId();
if (grp == null) {
grp = "null";
}
Integer salary = map.get(grp);
map.put(grp, salary == null ? e.getSalary() : e.getSalary() + salary);
}
// Result list
List<Employee> result = new ArrayList<>();
// Iterate the sorted entry set of `map` and put the records corresponding to
// an entry into the result list
for (Entry<String, Integer> entry : entriesSortedByValues(map)) {
String grp = entry.getKey();
int i;
// Find the starting index of `grp` in empList
if ("null".equals(grp)) {// Special handling for employees with `null` group
// Find the index in `empList` where employees with the group as `null` starts
for (i = 0; i < empList.size() && empList.get(i).getGroupId() != null; i++)
;
// Add elements before a different group is encountered
for (int j = i; j < empList.size() && empList.get(j).getGroupId() == null; j++) {
result.add(empList.get(j));
}
} else {
// Find the index in `empList` where employees with the group as `grp` starts
for (i = 0; i < empList.size() && !grp.equals(empList.get(i).getGroupId()); i++)
;
// Add elements before a different group is encountered
for (int j = i; j < empList.size() && grp.equals(empList.get(j).getGroupId()); j++) {
result.add(empList.get(j));
}
}
}
// Display result list
for (Employee e : result) {
System.out.println(e);
}
}
private static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues(
Map<K, V> map) {
SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
int res = e2.getValue().compareTo(e1.getValue());
return res != 0 ? res : 1;
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
}Output:
Employee [empId=emp6, groupId=grp2, salary=1000]
Employee [empId=emp4, groupId=grp2, salary=800]
Employee [empId=emp9, groupId=grp2, salary=600]
Employee [empId=emp8, groupId=null, salary=1000]
Employee [empId=emp3, groupId=null, salary=700]
Employee [empId=emp2, groupId=null, salary=600]
Employee [empId=emp7, groupId=grp1, salary=800]
Employee [empId=emp5, groupId=grp1, salary=700]
Employee [empId=emp1, groupId=grp1, salary=500]Note: The method,
entriesSortedByValues
has been copied from this post.
How to sort list based on multiple fields value in java
The thenComparing
is for nested sorting: when there are objects with equal values, they are then internally sorted by the next property.
What you apparently want is to define your own completely separate sort order:
list.sort(Comparator.comparing(o -> {
if (Boolean.TRUE.equals(o.getPassport()) {
return 1;
} else if (Boolean.FALSE.equals(o.getFeatured()) {
return 2;
} else if ("Cancelled".equals(o.getStatus()) {
return 3;
} else if ("Unconfirmed".equals(o.getStatus()) {
return 4;
} else {
return 5;
}
}));
Sort collection by multiple fields in Kotlin
sortedWith
+ compareBy
(taking a vararg of lambdas) do the trick:
val sortedList = list.sortedWith(compareBy({ it.age }, { it.name }))
You can also use the somewhat more succinct callable reference syntax:
val sortedList = list.sortedWith(compareBy(Person::age, Person::name))
Related Topics
Runnable Jars Missing Images/Files (Resources)
How to Automatically Generate N "Distinct" Colors
Does the Jvm Prevent Tail Call Optimizations
How to Retrieve Element Value of Xml Using Java
How to Create an .Exe for a Java Program
Java:If a Extends B and B Extends Object, Is That Multiple Inheritance
Why Doesn't Java Support Unsigned Ints
Exception Thrown in Catch and Finally Clause
How to Specify the Default Error Page in Web.Xml
Extract Digits from a String in Java
How to Include Jar Files with Java File and Compile in Command Prompt
Spring MVC @Pathvariable Getting Truncated