You can make your object comparable:
public static class MyObject implements Comparable<MyObject> {
private Date dateTime;
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date datetime) {
this.dateTime = datetime;
}
@Override
public int compareTo(MyObject o) {
return getDateTime().compareTo(o.getDateTime());
}
}
And then you sort it by calling:
Collections.sort(myList);
However sometimes you don't want to change your model, like when you want to sort on several different properties. In that case, you can create comparator on the fly:
Collections.sort(myList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getDateTime().compareTo(o2.getDateTime());
}
});
However, the above works only if you're certain that dateTime is not null at the time of comparison. It's wise to handle null as well to avoid NullPointerExceptions:
public static class MyObject implements Comparable<MyObject> {
private Date dateTime;
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date datetime) {
this.dateTime = datetime;
}
@Override
public int compareTo(MyObject o) {
if (getDateTime() == null || o.getDateTime() == null)
return 0;
return getDateTime().compareTo(o.getDateTime());
}
}
Or in the second example:
Collections.sort(myList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
if (o1.getDateTime() == null || o2.getDateTime() == null)
return 0;
return o1.getDateTime().compareTo(o2.getDateTime());
}
});
Answer from Domchi on Stack OverflowYou can make your object comparable:
public static class MyObject implements Comparable<MyObject> {
private Date dateTime;
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date datetime) {
this.dateTime = datetime;
}
@Override
public int compareTo(MyObject o) {
return getDateTime().compareTo(o.getDateTime());
}
}
And then you sort it by calling:
Collections.sort(myList);
However sometimes you don't want to change your model, like when you want to sort on several different properties. In that case, you can create comparator on the fly:
Collections.sort(myList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getDateTime().compareTo(o2.getDateTime());
}
});
However, the above works only if you're certain that dateTime is not null at the time of comparison. It's wise to handle null as well to avoid NullPointerExceptions:
public static class MyObject implements Comparable<MyObject> {
private Date dateTime;
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date datetime) {
this.dateTime = datetime;
}
@Override
public int compareTo(MyObject o) {
if (getDateTime() == null || o.getDateTime() == null)
return 0;
return getDateTime().compareTo(o.getDateTime());
}
}
Or in the second example:
Collections.sort(myList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
if (o1.getDateTime() == null || o2.getDateTime() == null)
return 0;
return o1.getDateTime().compareTo(o2.getDateTime());
}
});
Since Java 8 the List interface provides the sort method. Combined with lambda expression the easiest solution would be
// sort DateTime typed list
list.sort((d1,d2) -> d1.compareTo(d2));
// or an object which has an DateTime attribute
list.sort((o1,o2) -> o1.getDateTime().compareTo(o2.getDateTime()));
// or like mentioned by Tunaki
list.sort(Comparator.comparing(o -> o.getDateTime()));
Reverse sorting
Java 8 comes also with some handy methods for reverse sorting.
//requested by lily
list.sort(Comparator.comparing(o -> o.getDateTime()).reversed());
How to sort list by date using java
sort by date java basic list - Stack Overflow
java - Sort data by date - Stack Overflow
[Java] How do I sort an object arraylist by their date fields which are saved as strings?
You can do this with Comparator interface. I prefer to convert the string into date first.
For dd/MM/yyyy (01/01/1970) pattern example (without conversion):
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list, new Comparator<Ticket>() {
public int compare(Ticket t1, Ticket t2) {
String[] dateParts1 = t1.date.split("/");
String[] dateParts2 = t2.date.split("/");
int yearResult = dateParts1[2].compareTo(dateParts2[2]);
if (yearResult != 0) {
return yearResult;
}
int monthResult = dateParts1[1].compareTo(dateParts2[1]);
if (monthResult != 0) {
return monthResult;
}
int dayResult = dateParts1[0].compareTo(dateParts2[0]);
if (dayResult != 0) {
return dayResult;
}
return 0;
}
});
or (with conversion):
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list2, new Comparator<Ticket>() {
public int compare(Ticket t1, Ticket t2) {
String pattern = "dd/MM/yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try {
Date date1 = simpleDateFormat.parse(t1.date);
Date date2 = simpleDateFormat.parse(t2.date);
return date1.compareTo(date2);
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
});
Also, you can do same thing in class with Comparable interface.
public class Ticket **implements Comparable<Ticket>** {
int id;
String city;
String date;
int days;
float price;
String vehicle;
Ticket(int i, String c, String y, int d, float p, String v) {
id = i;
city = c;
date = y;
days = d;
price = p;
vehicle = v;
}
**@Override
public int compareTo(Ticket o) {
String[] dateParts1 = this.date.split("/");
String[] dateParts2 = o.date.split("/");
int yearResult = dateParts1[2].compareTo(dateParts2[2]);
if (yearResult != 0) {
return yearResult;
}
int monthResult = dateParts1[1].compareTo(dateParts2[1]);
if (monthResult != 0) {
return monthResult;
}
int dayResult = dateParts1[0].compareTo(dateParts2[0]);
if (dayResult != 0) {
return dayResult;
}
return 0;
}**
}
Then:
List<Ticket> list = new LinkedList<Ticket>();
... //fill the list.
Collections.sort(list);
You can parse the date String to a date object like LocalDateTime or Instant and etc' (depending on your use case).
I randomly picked LocalDateTime for this example.
Then you can do:
tickets.add(new Ticket(1, "dsa", LocalDateTime.now().plusSeconds(5), 6, 5, "rew"));
tickets.add(new Ticket(0, "dsa", LocalDateTime.now(), 6, 5, "rew"));
List<Ticket> sortedTicketsByDate = tickets.stream()
.sorted(Comparator.comparing(t -> t.date)) // comparing by date
.collect(Collectors.toList());
System.out.println(sortedTicketsByDate);
Output:
[
Ticket(id=0, city=dsa, date=2021-05-02T23:46:03.214, days=6, price=5.0, vehicle=rew),
Ticket(id=1, city=dsa, date=2021-05-02T23:46:08.197, days=6, price=5.0, vehicle=rew)
]
You would need to create class say Data and then implement Comparable in that like:
public class Data implements Comparable<Data> {
private String name;
private Date startDate;
...//other fields
...//getter setter
public int compareTo(Data otherData) {
return this.startDate.compareTo(otherData.startDate);
}
}
Then read and create a list of records like:
List<Data> dataList = ....
//read file and add data to list
Collections.sort(dataList);
It depends on the characteristics of your dataset and what you want to do with it afterwards. If you just want to have it sorted by date, then @SMA's answer is good. You might also want to, assuming start dates are unique, use the date as a key to find a particular record: look into SortedMap<Date,T> if that's your preferred route.
I'm stuck and can't figure out how to sort it, haven't been able to implement the solutions of using comperator I've found online and I'm just very confused.
So I have a Trip object arraylist which contains a date field saved as a string "DD/MM/YYYY"
How would I go about sorting the list by the dates?
I think that you can create a custom comparator with an structure similar to the below:
Collections.sort(datestring, new Comparator<String>() {
DateFormat df = new SimpleDateFormat("your format");
@Override
public int compare(String s1, String s2) {
try {
return df.parse(s1).compareTo(df.parse(s2));
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
});
Basically you need to convert the timezones to dates as part of the sorting operation:
schedules.sort((s1, s2) -> {
ZonedDateTime d1 = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(s1.getStartDate(), ZonedDateTime::from);
ZonedDateTime d2 = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(s2.getStartDate(), ZonedDateTime::from);
return d1.compareTo(d2);
});
I assume you have two different classes and both having Date objects. Instead of keeping list of objects I would suggest you creating a base interface like for example:
interface Dated {
Date getDate();
}
Make your two classes implements this interface:
class A implements Dated {
int id;
Date date;
@Override
public Date getDate() {
return date;
}
}
class B implements Dated {
int id;
Date date;
@Override
public Date getDate() {
return date;
}
}
Create a Comparator like:
class DatedComparator implements Comparator<Dated> {
@Override
public int compare(Dated o1, Dated o2) {
return o1.getDate().compareTo(o2.getDate());
}
}
Then you can hold a list of Dated objects:
List<Dated> finalList = new ArrayList<Dated>();
which can be easily sorted by using your comparator:
Collections.sort(finalList, new DatedComparator());
I assume it's not an option for you to make the different types in your list compatible. But if odering is really your only problem here you could user an adaptive comparator for sorting:
class DateOrder implements Comparator<Object> {
@Override
public int compare(Objecto1, Objecto2) {
return toDate(o1).compareTo(toDate(o2));
}
private Date toDate(Object x) {
if (x instanceof A) {
return ((A)x).date;
}
return ((B)x).date;
}
}
However having several different types in a single collection is typically not a good idea. So maybe it's better to use an instance adapter (i.e. to wrappers to provide a unique interface to the logic working on that types.) In most cases this approach is more valueable on the longer term as it's not necessary to cast over and over again just to get yet another part of the data. But I don't know enough about your problem to give a clear advice.