I have the following problem to solve. I am using Java.
A restaurant recognizes 3 types of customers: “NEWBIES”, “REGULARS” and “VIPs”. When customers place their orders, all the orders join a queue. However the orders are always served in such a way that VIPs are served before regulars who are served before newbies.
I need a class which could be used to sort the customer orders. In case two customers are of the same type, the orderID should be used to sort them.
How can I sort by order priority based on the customer type using comparator?
Assuming I already have the following class Order
public class Order
{
public static int orderID;
private int tableNumber;
private String[] orderDetails;
private String customerType;
public Order(int tableNumber, String[] orderDetails, String customerType)
{
this.tableNumber = tableNumber;
this.orderDetails = orderDetails;
this.customerType = customerType;
orderID += 1;
}
// get and set methods declared
}
I have implemented the comparator as follows:
import java.util.Comparator;
public class OrderComparator implements Comparator<Order>
{
#Override
public int compare(Order o1, Order o2)
{
if(o1.getType().equals(o2.getType()))
return o1.getOrderID - o2.getOrderID;
else
// How does comparing the customer type text ensure that
// it will be printed in the right order?
return o1.getType().compareTo(o2.getType());
}
}
Not only do you want to sort on multiple fields, you also want a custom sort with one of those fields.
In the code below, I filled in the missing parts of both class Order and class OrderComparator. Notes after the code.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Order {
public static final String NEWBIES = "NEWBIES";
public static final String REGULARS = "REGULARS";
public static final String VIP = "VIP";
private static int orderId;
private int orderID;
private int tableNumber;
private String[] orderDetails;
private String customerType;
public Order(int tableNumber, String[] orderDetails, String customerType) {
this.tableNumber = tableNumber;
this.orderDetails = orderDetails;
this.customerType = customerType;
orderID = ++orderId;
}
public int getOrderID() {
return orderID;
}
public int getTableNumber() {
return tableNumber;
}
public String[] getOrderDetails() {
return orderDetails;
}
public String getType() {
return customerType;
}
public String toString() {
return String.format("%d %s", orderID, customerType);
}
public static void main(String[] args) {
Order order1 = new Order(0, null, VIP);
Order order2 = new Order(0, null, REGULARS);
Order order3 = new Order(0, null, REGULARS);
List<Order> list = new ArrayList<>();
list.add(order3);
list.add(order2);
list.add(order1);
System.out.println("Unordered: " + list);
Collections.sort(list, new OrderComparator());
System.out.println("Ordered: " + list);
}
}
class OrderComparator implements Comparator<Order> {
#Override
public int compare(Order o1, Order o2) {
if (o1.getType().equals(o2.getType())) {
return o1.getOrderID() - o2.getOrderID();
}
else {
if (Order.VIP.equals(o1.getType())) {
return -1;
}
else if (Order.VIP.equals(o2.getType())) {
return 1;
}
else if (Order.REGULARS.equals(o1.getType())) {
return -1;
}
else if (Order.REGULARS.equals(o2.getType())) {
return 1;
}
else if (Order.NEWBIES.equals(o1.getType())) {
return -1;
}
else if (Order.NEWBIES.equals(o2.getType())) {
return 1;
}
throw new RuntimeException("Unexpected customer type.");
}
}
}
I added method main to class Order in order to test the code.
I added method toString to class Order so as to be able to check whether the code produces the expected results.
I understand that you want a kind of numerator for Order objects. Hence I made member orderID an instance member since every Order has its own ID and I added a new static member orderId (note that Java is case sensitive) which produces a new, unique order ID for each new Order object.
You want VIP orders to come before REGULARS orders and you want REGULARS orders to come before NEWBIES orders. By default, a Comparator sorts by ascending order, hence you want VIP to be lowest and NEWBIES to be highest (purely for sorting purposes). So in method compare (of class OrderComparator), if, for example, the type of o1 is VIP and the type of o2 is REGULARS then you want VIP to be lower that REGULAR. Hence in that situation, method compare returns -1 (minus one).
Running the above code produces the following output.
Unordered: [3 REGULARS, 2 REGULARS, 1 VIP]
Ordered: [1 VIP, 2 REGULARS, 3 REGULARS]
Note that since customerType (in class Order) is a String, there is a chance that an Order object will be created with an invalid customerType value. You could change the constructor of class Order and add a check for the supplied value (for customerType) and throw an Exception if the supplied value is invalid. Or you could use enum (also known as enumerated types). The below code uses enum instead of String for customerType - which also simplifies method compare in class OrderComparator.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Order {
private static int orderId;
private int orderID;
private int tableNumber;
private String[] orderDetails;
private CustomerType customerType;
public Order(int tableNumber, String[] orderDetails, CustomerType customerType) {
this.tableNumber = tableNumber;
this.orderDetails = orderDetails;
this.customerType = customerType;
orderID = ++orderId;
}
public int getOrderID() {
return orderID;
}
public int getTableNumber() {
return tableNumber;
}
public String[] getOrderDetails() {
return orderDetails;
}
public CustomerType getType() {
return customerType;
}
public String toString() {
return String.format("%d %s", orderID, customerType);
}
public static void main(String[] args) {
Order order1 = new Order(0, null, CustomerType.VIP);
Order order2 = new Order(0, null, CustomerType.REGULARS);
Order order3 = new Order(0, null, CustomerType.REGULARS);
List<Order> list = new ArrayList<>();
list.add(order3);
list.add(order2);
list.add(order1);
System.out.println("Unordered: " + list);
Collections.sort(list, new OrderComparator());
System.out.println("Ordered: " + list);
}
}
class OrderComparator implements Comparator<Order> {
#Override
public int compare(Order o1, Order o2) {
if (o1.getType().equals(o2.getType())) {
return o1.getOrderID() - o2.getOrderID();
}
else {
return o2.getType().ordinal() - o1.getType().ordinal();
}
}
}
enum CustomerType {
NEWBIES, REGULARS, VIP
}
You can read this question How to sort a collection by multiple fields. Especially the second answer, first option listed.
I´m having troubles to define a method that sort a list of the same class where is defined this method.
For example the class is defined with the following attributes:
public abstract class Licence {
//other attributes
protected List<People> myList;
//Constructor and other methods
//The method I want
public List<People> getPeopleInOrder ( Comparator c)
List<People> aux = new ArrayList<People>(this.myList);
Collections.sort(aux, c);
return aux;
And also I have this class
class CompPeople implements Comparator<People>{
public int compare( People e1, People e2) {
// Declaration the criteria of comparison
if ( c1 == 0) {
if (c2 == 0 ) return c3;
else return c2;
}
else return c1;
}
}
But when I call in main method
List<People> myNewList = Mylicence.getPeopleInOrder(new CompPeople());
EDIT: Before I was trying to sort a unmodifiable list, I changed it and now it gives me empty list.
I know I can use the method sort of Collections but what I want is a method of class Licence that sort its list with a given comparator. Thanks in advance
I think you have incorrect comparator.
Let define a People class:
public class People {
private String name;
private String city;
}
In case you plan to use different ways to compare these object, then it is better to use custom comparators. E.g. this is two comparators that sort people by one of the field. I recommend to define different comparators as part of People class:
public class People {
private String name;
private String city;
public static final Comparator<People> SORT_BY_NAME_ASC = (one, two) -> one.name.compareToIgnoreCase(two.name);
public static final Comparator<People> SORT_BY_CITY_ASC = (one, two) -> one.city.compareToIgnoreCase(two.city);
}
Now you can use it sort List<People> peoples:
people.sort(People.SORT_BY_NAME_ASC); // sort by name asc
people.sort(People.SORT_BY_CITY_ASC); // sort by city asc
people.sort(People.SORT_BY_NAME_ASC.thenComparing(People.SORT_BY_CITY_ASC)); // sort by name and city asc
You method getPeopleInOrder() could look like this:
public List<People> getPeopleInOrder(Comparator<People> comparator) {
if(myList.isEmpty())
return Collections.emptyList();
List<People> aux = new ArrayList<>(myList);
aux.sort(comparator);
return aux;
}
...or using Streams like this:
public List<People> getPeopleInOrder(Comparator<People> comparator) {
return myList.stream().sorted(comparator).collect(Collectors.toList());
}
In case you want only one comparator, then you have two ways.
class People implements Comparable
class People implements Comparable<People> {
private String name;
private String city;
#Override
public int compareTo(People people) {
int res = name.compareToIgnoreCase(people.name);
res = res == 0 ? city.compareToIgnoreCase(people.city) : res;
// compare other fields you want
return res;
}
}
Use single Comparator
public class People {
private String name;
private String city;
public static final Comparator<People> SORTY_BY_NAME_AND_CITY = (one, two) -> {
int res = one.name.compareToIgnoreCase(two.name);
res = res == 0 ? one.city.compareToIgnoreCase(two.city) : res;
// compare other fields you want
return res;
};
}
As you should be able to guess from the comment, the problem is the unmodifiableList(). For a copy, just create a new List.
public List<People> getPeopleInOrder ( Comparator c)
List<People> aux = new ArrayList<>(this.myList);
Collections.sort(aux, c);
return aux;
}
I have four ArrayLists. I want to sort one of them alphabetically with case ignored and do the same changes in the other three ArrayLists.
ArrayList<String> arrPackage = new ArrayList<>();
ArrayList<String> arrPackageDates = new ArrayList<>();
ArrayList<String> arrPackageDuration = new ArrayList<>();
ArrayList<String> arrPackageFileSize = new ArrayList<>();
// Code to add data to ArrayLists (data is not coming from sqlite database)
...
// Code to sort arrPackage alphabatically with case ignored
Collections.sort(arrPackage, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
});
but how do I know which indexes were changed?
One approach would be to create a wrapper object Package which contains the four types of metadata which appears in the four current lists. Something like this:
public class Package {
private String name;
private String date;
private String duration;
private String fileSize;
public Package() {
// can include other constructors as well
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// other getters and setters
}
Then sort using a custom comparator which works on Package objects:
List<Package> packages = new ArrayList<>();
Collections.sort(packages, new Comparator<Package>() {
#Override
public int compare(Package p1, Package p2) {
String name1 = p1.getName();
String name2 = p2.getName();
return name1.compareToIgnoreCase(name2);
}
});
As a general disclaimer, the above operation would most likely be performed must more efficiently in a database. So if your data is ultimately coming from a database, you should try to do such heavy lifting there.
A simple easy way would be backing up your ArrayList.
ArrayList<String> backupPackage = arrPackage;
And then use your code to sort the array. Then use a for loop to compare the two arrays.
for (int i = 0; i < backupArray.size(); i++) {
if (!aar.get(i).equals(aar.get(i))) { // then the item has been changed
// ... YOUR CODE
// at this point you know which indexes have been changed and can modify your other arrays in any way you need
}
}
I used this approach:
ArrayList<String> backupPackage = new ArrayList<>();
ArrayList<String> backupPackageDates = new ArrayList<>();
ArrayList<String> backupPackageDuration = new ArrayList<>();
ArrayList<String> backupPackageFileSize = new ArrayList<>();
for(int j=0;j<arrPackage.size();j++) {
backupPackage.add(arrPackage.get(j));
}
for(int j=0;j<arrPackageDates.size();j++) {
backupPackageDates.add(arrPackageDates.get(j));
}
for(int j=0;j<arrPackageDuration.size();j++) {
backupPackageDuration.add(arrPackageDuration.get(j));
}
for(int j=0;j<arrPackageFileSize.size();j++) {
backupPackageFileSize.add(arrPackageFileSize.get(j));
}
Collections.sort(arrPackage, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
});
int newindex;
for(int i=0; i<backupPackage.size(); i++) {
newindex = backupPackage.indexOf(arrPackage.get(i));
if(newindex != i) {
arrPackageDates.set(i, backupPackageDates.get(newindex));
arrPackageDuration.set(i, backupPackageDuration.get(newindex));
arrPackageFileSize.set(i, backupPackageFileSize.get(newindex));
}
}
backupPackage.clear();
backupPackageDuration.clear();
backupPackageDuration.clear();
backupPackageFileSize.clear();
I have simple class
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
and List<ActiveAlarm> con. How to sort in ascending order by timeStarted, then by timeEnded? Can anybody help? I know in C++ with generic algorithm and overload operator <, but I am new to Java.
Using Comparator
For Example:
class Score {
private String name;
private List<Integer> scores;
// +accessor methods
}
Collections.sort(scores, new Comparator<Score>() {
public int compare(Score o1, Score o2) {
// compare two instance of `Score` and return `int` as result.
return o2.getScores().get(0).compareTo(o1.getScores().get(0));
}
});
With Java 8 onwards, you can simply use lambda expression to represent Comparator instance.
Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });
Either make ActiveAlarm implement Comparable<ActiveAlarm> or implement Comparator<ActiveAlarm> in a separate class. Then call:
Collections.sort(list);
or
Collections.sort(list, comparator);
In general, it's a good idea to implement Comparable<T> if there's a single "natural" sort order... otherwise (if you happen to want to sort in a particular order, but might equally easily want a different one) it's better to implement Comparator<T>. This particular situation could go either way, to be honest... but I'd probably stick with the more flexible Comparator<T> option.
EDIT: Sample implementation:
public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
#Override
public int compare(ActiveAlarm x, ActiveAlarm y) {
// TODO: Handle null x or y values
int startComparison = compare(x.timeStarted, y.timeStarted);
return startComparison != 0 ? startComparison
: compare(x.timeEnded, y.timeEnded);
}
// I don't know why this isn't in Long...
private static int compare(long a, long b) {
return a < b ? -1
: a > b ? 1
: 0;
}
}
JAVA 8 and Above Answer (Using Lambda Expressions)
In Java 8, Lambda expressions were introduced to make this even easier! Instead of creating a Comparator() object with all of it's scaffolding, you can simplify it as follows: (Using your object as an example)
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);
or even shorter:
Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));
That one statement is equivalent to the following:
Collections.sort(list, new Comparator<ActiveAlarm>() {
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return a1.timeStarted - a2.timeStarted;
}
});
Think of Lambda expressions as only requiring you to put in the relevant parts of the code: the method signature and what gets returned.
Another part of your question was how to compare against multiple fields. To do that with Lambda expressions, you can use the .thenComparing() function to effectively combine two comparisons into one:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted
.thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);
The above code will sort the list first by timeStarted, and then by timeEnded (for those records that have the same timeStarted).
One last note: It is easy to compare 'long' or 'int' primitives, you can just subtract one from the other. If you are comparing objects ('Long' or 'String'), I suggest you use their built-in comparison. Example:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );
EDIT: Thanks to Lukas Eder for pointing me to .thenComparing() function.
We can sort the list in one of two ways:
1. Using Comparator : When required to use the sort logic in multiple places
If you want to use the sorting logic in a single place, then you can write an anonymous inner class as follows, or else extract the comparator and use it in multiple places
Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
public int compare(ActiveAlarm o1, ActiveAlarm o2) {
//Sorts by 'TimeStarted' property
return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
}
//If 'TimeStarted' property is equal sorts by 'TimeEnded' property
public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
}
});
We can have null check for the properties, if we could have used 'Long' instead of 'long'.
2. Using Comparable(natural ordering): If sort algorithm always stick to one property:
write a class that implements 'Comparable' and override 'compareTo' method as defined below
class ActiveAlarm implements Comparable<ActiveAlarm>{
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(long timeStarted,long timeEnded) {
this.timeStarted=timeStarted;
this.timeEnded=timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
public int compareTo(ActiveAlarm o) {
return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}
public int doSecodaryOrderSort(ActiveAlarm o) {
return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}
}
call sort method to sort based on natural ordering
Collections.sort(list);
In java8+ this can be written in single line as follows:
collectionObjec.sort(comparator_lamda) or comparator.comparing(CollectionType::getterOfProperty)
code:
ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
or
ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
public class ActiveAlarm implements Comparable<ActiveAlarm> {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public int compareTo(ActiveAlarm a) {
if ( this.timeStarted > a.timeStarted )
return 1;
else if ( this.timeStarted < a.timeStarted )
return -1;
else {
if ( this.timeEnded > a.timeEnded )
return 1;
else
return -1;
}
}
That should give you a rough idea. Once that's done, you can call Collections.sort() on the list.
Since Java8 this can be done even cleaner using a combination of Comparator and Lambda expressions
For Example:
class Student{
private String name;
private List<Score> scores;
// +accessor methods
}
class Score {
private int grade;
// +accessor methods
}
Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);
Java-8 solution using Stream API:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded))
.collect(Collectors.toList());
B. When timeStarted and timeEnded have public getter methods:
List<ActiveAlarm> sorted =
list.stream()
.sorted(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded))
.collect(Collectors.toList());
If you want to sort the original list itself:
A. When timeStarted and timeEnded are public (as mentioned in the requirement) and therefore do not (need to) have public getter methods:
list.sort(Comparator.comparingLong((ActiveAlarm alarm) -> alarm.timeStarted)
.thenComparingLong((ActiveAlarm alarm) -> alarm.timeEnded));
B. When timeStarted and timeEnded have public getter methods:
list.sort(Comparator.comparingLong(ActiveAlarm::getTimeStarted)
.thenComparingLong(ActiveAlarm::getTimeEnded));
Guava's ComparisonChain:
Collections.sort(list, new Comparator<ActiveAlarm>(){
#Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return ComparisonChain.start()
.compare(a1.timestarted, a2.timestarted)
//...
.compare(a1.timeEnded, a1.timeEnded).result();
}});
We can use the Comparator.comparing() method to sort a list based on an object's property.
class SortTest{
public static void main(String[] args) {
ArrayList<ActiveAlarm> activeAlarms = new ArrayList<>(){{
add(new ActiveAlarm("Alarm 1", 5, 10));
add(new ActiveAlarm("Alarm 2", 2, 12));
add(new ActiveAlarm("Alarm 3", 0, 8));
}};
/* I sort the arraylist here using the getter methods */
activeAlarms.sort(Comparator.comparing(ActiveAlarm::getTimeStarted)
.thenComparing(ActiveAlarm::getTimeEnded));
System.out.println(activeAlarms);
}
}
Note that before doing it, you'll have to define at least the getter methods of the properties you want to base your sort on.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
public ActiveAlarm(String name, long timeStarted, long timeEnded) {
this.name = name;
this.timeStarted = timeStarted;
this.timeEnded = timeEnded;
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeEnded() {
return timeEnded;
}
#Override
public String toString() {
return name;
}
}
Output:
[Alarm 3, Alarm 2, Alarm 1]
Employee POJO Class
package in.ac.adit.oop.sort;
public class Employee {
private int id;
private String name;
private String department;
public int getId() {
return id;
}
public Employee() {
super();
}
public Employee(int id, String name, String department) {
super();
this.id = id;
this.name = name;
this.department = department;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
Employee Class To Manage Employee
package in.ac.adit.oop.sort;
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String[] args) {
/*
* Create 10 Employee Object
*/
Employee emp1 = new Employee(1, "Nayan", "IT");
Employee emp2 = new Employee(2, "Siddarth", "CP");
Employee emp3 = new Employee(3, "Samarth", "AE");
Employee emp4 = new Employee(4, "Bhavesh", "CV");
Employee emp5 = new Employee(5, "Sam", "FT");
Employee emp6 = new Employee(6, "Keyur", "IT");
Employee emp7 = new Employee(7, "Bala", "ME");
Employee emp8 = new Employee(8, "Mitul", "ME");
Employee emp9 = new Employee(9, "Kamlesh", "EE");
Employee emp10 = new Employee(10, "Piyush", "EE");
/*
* List of Employee Object
*/
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);
employeeList.add(emp4);
employeeList.add(emp5);
employeeList.add(emp6);
employeeList.add(emp7);
employeeList.add(emp8);
employeeList.add(emp9);
employeeList.add(emp10);
CustomObjectSort customObjectSort = new CustomObjectSort();
List<Employee> sortByDepartment = customObjectSort.sortByDepartment(employeeList);
/*
* Sorted By Department
*/
for (Employee employee : sortByDepartment) {
System.out.println(employee);
}
/*
* Sorted By Name
*/
List<Employee> sortByName = customObjectSort.sortByName(employeeList);
for (Employee employee : sortByName) {
System.out.println(employee);
}
/*
* Sorted By Id
*/
List<Employee> sortById = customObjectSort.sortById(employeeList);
for (Employee employee : sortById) {
System.out.println(employee);
}
}
}
Custom Sorting
package in.ac.adit.oop.sort;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CustomObjectSort {
public List<Employee> sortByName(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getName().compareTo(employee2.getName());
}
});
return employeeList;
}
public List<Employee> sortByDepartment(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getDepartment().compareTo(employee2.getDepartment());
}
});
return employeeList;
}
public List<Employee> sortById(List<Employee> employeeList) {
Collections.sort(employeeList, new Comparator<Employee>() {
#Override
public int compare(Employee employee1, Employee employee2) {
return employee1.getId() - employee2.getId();
}
});
return employeeList;
}
}
You can use Collections.sort and pass your own Comparator<ActiveAlarm>
In java you need to use the static Collections.sort method. Here is an example for a list of CompanyRole objects, sorted first by begin and then by end. You can easily adapt for your own object.
private static void order(List<TextComponent> roles) {
Collections.sort(roles, new Comparator() {
#Override
public int compare(Object o1, Object o2) {
int x1 = ((CompanyRole) o1).getBegin();
int x2 = ((CompanyRole) o2).getBegin();
if (x1 != x2) {
return x1 - x2;
} else {
int y1 = ((CompanyRole) o1).getEnd();
int y2 = ((CompanyRole) o2).getEnd();
return y2 - y1;
}
}
});
}
You can call Collections.sort() and pass in a Comparator which you need to write to compare different properties of the object.
As mentioned you can sort by:
Making your object implement Comparable
Or pass a Comparator to Collections.sort
If you do both, the Comparable will be ignored and Comparator will be used. This helps that the value objects has their own logical Comparable which is most reasonable sort for your value object, while each individual use case has its own implementation.
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}
List<ActiveAlarm> con = new ArrayList<ActiveAlarm>();
Collections.sort(con , (a1, a2) -> a1.timeStarted.compareTo(a2.timeStarted));
Collections.sort(con , (a1, a2) -> a1.timeEnded.compareTo(a2.timeEnded));
Here's what did the trick for me.
Was much shorter and easier than everything else I found:
Collections.sort(listName, Comparator.comparing(Object::getProperty).reversed());
The ".reversed()" part at the end was a requirement for my specific project but I'm sharing it too, as it took a while to find it
The best and the easiest way to sort any list of objects in Java (Java 8 and above).
Lets sort a basket of fruits based on the property "fruitName"
Fruit POJO:
class Fruit
{
int price;
String fruitName;
public Fruit(int price, String fruitName) {
super();
this.price = price;
this.fruitName = fruitName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
#Override
public String toString() {
return "Fruits [price=" + price + ", fruitName=" + fruitName + "]";
}
}
Now lets add fruits into a list and then sort it
List<Fruit> basketOfFruits = new ArrayList<>();
basketOfFruits.add(new Fruit(123, "oranges"));
basketOfFruits.add(new Fruit(45, "nectarine"));
basketOfFruits.add(new Fruit(369, "blueberries"));
basketOfFruits.add(new Fruit(248, "apple"));
basketOfFruits.add(new Fruit(968, "peaches"));
basketOfFruits.add(new Fruit(436, "grapes"));
basketOfFruits.add(new Fruit(596, "figs"));
//sorting by the property fruitName
Collections.sort(basketOfFruits, (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());});
You can now print the list (i.e basketOfFruits) and the fruits in the list would be sorted in ASCENDING order (lexicographically).
The output would look like this:
[Fruits [price=248, fruitName=apple], Fruits [price=369, fruitName=blueberries], Fruits [price=596, fruitName=figs], Fruits [price=436, fruitName=grapes], Fruits [price=45, fruitName=nectarine], Fruits [price=123, fruitName=oranges], Fruits [price=968, fruitName=peaches]]
Instead of Collections.sort(), Java streams can also be used (Java 8 and above). The following is the code using Java streams
List<Fruit> sortedFruits = basketOfFruits.stream().sorted( (f1, f2)->{return f1.getFruitName().compareTo(f2.getFruitName());}).collect(Collectors.toList());
here the list is sorted in the same manner as Collections.sort(), but the sorted items would be stored/collected in another list "sortedFruits". So, if we want to print the sorted items of the list, we need to print "sortedFruits" instead of "basketOfFruits" in this case
I want to sort an ArrayList of objects on a specific field using a given RuleBasedCollator.
For example, we have a list of Thing objects:
public Thing {
public String name;
public String type;
}
List<Thing> things = new ArrayList<Thing>();
RuleBasedCollator ruleBasedCollator = new RuleBasedCollator("< Table < Plate < Fork < Knife");
Now, after having created Thing objects and added them to the things list, I want to sort this list, getting first things of type "table" and last things of type "knife".
Does anyone know how to do it?
You can try something like this, instead of using compareTo in compare method of Comparator you can call RuleBasedCollator's compare.
mQueue.sort((o1, o2) -> {
if (o1.getDescription().getTitle() != null && o2.getDescription().getTitle() != null) {
return mRuleBasedCollator.compare(o1.getDescription().getTitle().toString(),
o2.getDescription().getTitle().toString());
} else {
return 0;
}
});
As far as I understand a RuleBaseCollator is intended for sorting Strings, at least i says so in the Collator class which is the super class. I would instead use a Comparator, something like this:
public class ThingSorter {
public enum ThingType{
//wanted sort order, sort on ordinal :
//Table < Plate < Fork < Knife
TABLE, PLATE, FORK, KNIFE
}
public static class Thing {
private String name;
private ThingType type;
public Thing(String name, ThingType tt) {
this.name = name;
type = tt;
}
public String toString() {
return name + " [" + type + "]";
}
}
public static class MyThingComparator implements Comparator<Thing> {
#Override
public int compare(Thing t1, Thing t2) {
return t1.type.ordinal() - t2.type.ordinal();
}
}
public static class MyReverseThingComparator implements Comparator<Thing> {
#Override
public int compare(Thing t1, Thing t2) {
return t2.type.ordinal() - t1.type.ordinal();
}
}
public static void main(String[] args) throws ParseException {
List<Thing> things = new ArrayList<Thing>();
things.add(new Thing("One", ThingType.KNIFE));
things.add(new Thing("Two", ThingType.FORK));
things.add(new Thing("Three", ThingType.PLATE));
things.add(new Thing("Four", ThingType.TABLE));
System.out.println("unsorted:\n" + things);
Collections.sort(things, new MyThingComparable());
System.out.println("sorted:\n" + things);
Collections.sort(things, new MyReverseThingComparable());
System.out.println("sorted:\n" + things);
}
}
The names are are not involved in the sorting in this case just the type (and the ordinal in the type)
You could certainly use the TreeMap or enum as the previous answers suggest; a rather simpler alternative is to use just a custom compatator, without the enum. If you're using Java 8 you can get it down to a single line:
Collections.sort(things,
(Thing t1, Thing t2)->ruleBasedCollator.compare(t1.type, t2.type) );
The pre-8 version would do the same thing with an anonymous Comparator
I finally found a solution using a TreeMap. I use the "type" property for the key and a list of Thing for the value. Instead of using a RuleBasedCollator, I created a ListBasedCollator extending Collator, because RuleBasedCollator rules work on characters but not on words.
public class ListBasedCollator extends Collator {
private List<String> list;
public ListBasedCollator(String[] array) {
list = Arrays.asList(array);
}
#Override
public int compare(String source, String target) {
if(!list.contains(target)) {
return 1;
}
if(!list.contains(source)) {
return -1;
}
return Integer.valueOf(list.indexOf(source)).compareTo(Integer.valueOf(list.indexOf(target)));
}
#Override
public CollationKey getCollationKey(String source) {
return null;
}
#Override
public int hashCode() {
return 0;
}
}
Here is how I construct the TreeMap:
String[] sortingList = {"TABLE", "PLATE", "FORK", "KNIFE"};
ListBasedCollator listBasedCollator = new ListBasedCollator(sortingList);
Map<String, List<Thing>> thingMap = new TreeMap<String, List<Thing>>(listBasedCollator);
So, the thingMap will always be sorted by type using the listBasedCollator.
And I can also sort alphabetically the list of things for each different type.