I need to compare the attribute "date" of objects included in an ArrayList.
The objects included in the ArrayList are of type "Books" and each Book has a launching date.
The date is given in a String format.
public ArrayList<Book> group;
What I have done is :
public static Comparator<Book> ComparaisonDate = new Comparator<Book>() {
SimpleDateFormat data = new SimpleDateFormat("dd/mm/yyyy");
#Override
public int compare(Book l1, Book l2) {
try {
return data.parse(l1.launchingDate).compareTo(data.parse(l2.launchingDate));
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
};
public void sort(int option) {
Collections.sort(this.group, Book.ComparaisonDate);
}
When I add two books with the dates: 01/08/2020 and 12/05/2020 the result of the sort() function is:
01/08/2020
12/05/2020
The result should be: 12/05/2020 and then 01/05/2020.From what I can see, it compares only the day and not the month or year. Do you have any idea how to fix this? thanks
mm in the pattern stands for Minutes of the Hour, therefore the sorting is actually correct. You need MM. See https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html for valid patterns.
Related
This question already has answers here:
Sorting by two fields of object. Java
(1 answer)
Sort objects in ArrayList by date?
(14 answers)
Closed 2 years ago.
I am adding a feature in my app which lets the user fill entries for past dates, if today is 14/03/2020 then it lets you fill entries for 10/03/2020(or any other date). But I am Having a problem with sorting my arraylist such that all the entries with same dates are together in the arraylist.
I show the entries to the user in a custom ListView and so to make my app user friendly I want to make all those entries with the same date to appear together.
I have a custom arraylist which accepts a Expense Name(String),Amount(String) and Date(String)
ArrayList<ExpenseData> customArrayList=new ArrayList<ExpenseData>();
If you need any other information please ask... Thank You!
You can use below method to sort your list by date.
Collections.sort(list, (item1, item2) -> {
Date date1 = stringToDate(item1.getDate());
Date date2 = stringToDate(item2.getDate());
if (date1 != null && date2 != null) {
boolean b1;
boolean b2;
if (isAscending) {
b1 = date2.after(date1);
b2 = date2.before(date1);
}else {
b1 = date1.after(date2);
b2 = date1.before(date2);
}
if (b1 != b2) {
if (b1) {
return -1;
}
if (!b1) {
return 1;
}
}
}
return 0;
});
public static Date stringToDate(String strDate) {
if (strDate == null)
return null;
// change the date format whatever you have used in your model class.
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a", Locale.US);
Date date = null;
try {
date = format.parse(strDate);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
It is very bad practice to directly store Date or Time as String.
Instead you have store the Date or Time as Epoch value (Integer). That way you will have a lot of flexibility while displaying as well as Sorting or other operations.
And you can sort it in Increasing order for Old to New, Decreasing order for New to Old.
Hope it helps
You can easily sort the data in the required format by using Comparable or Comparator.
Your ExpenseData class which contains the date can implement Comparable interface and override the compareTo() method, where you define the logic to sort the dates.
For complete and detailed tutorial refer below this.
Here follow two pieces of code, and I know that it's not working as intended.
The Date instance is not supposed to be able to change after it's created, but because the getDate method returns an array(reference), it's able to change in the second part of my provided code with int[] dateValue = date.getDate ();.
I think I'm overthinking this a bit, and need a fresh pair of eyes on the problem.
Am I just supposed to build the Date-class with int y, int m, int d instead of int[] ymd or can I modify the return method and/or add a few more methods to either Date or Problem2?
Any ideas for how to fix this in the best or easiest way? The class Problem2 should print out the same thing both times, and/or the Date-instance should NOT be changeable!
As for now, I don't even know in what direction I should be thinking.
public class Date
{
private int[] ymd = new int[3];
public Date (int year, int month, int day)
{
ymd[0] = year;
ymd[1] = month;
ymd[2] = day;
}
public int[] getDate ()
{
return ymd;
}
public void printDate ()
{
System.out.println (ymd[0] + "-" + ymd[1] + "-" + ymd[2]);
}
}
public class Problem2
{
public static void main (String[] args)
{
Date date = new Date (2019, 6, 15);
date.printDate ();
int[] dateValue = date.getDate ();
dateValue[2] = 38;
date.printDate ();
}
}
As for now, Problem2 prints out:
2019-6-15
2019-6-38
When "fixed", it should print the same date both times.
To make the object immutable, you should return a copy of the array in the getDate() method.
To do this, you can replace the method by:
public int[] getDate ()
{
return Arrays.copyOf(ymd, ymd.length);
}
Arrays.copyOf take the array and his length as parameter. The it returns a copy of the array.
I'm trying to write a getter which takes specific data from an enum and returns a double, which I will use later in my code and I'm not sure how to go about it. This is what I've come up with so far:
//This getter takes the enum of Month and converts it so it returns the mean precipitation of a certain month
public double getPrecipitationMonth(Month month){
//more in here
return this.precipitationMonths[month.ordinal()];
The enum in question is the months of the year ie {JANUARY, FEBRUARY...} and the data for each month is in a separate file.
I'm new to programming - hope you can help! Thank you
I think your general idea is very sound. But I'd just use a Map like so:
Map<Month,Double> data = new HashMap<>;
for(Row row : readFromFile()){
data.put(row.getMonth(), row.getData());
}
So that it's more obvious.
You can use a HashMap for this, assigning enum values as keys
enum Month {
// Your enum
}
HashMap< Month, Double > monthPrecipitation = new HashMap< Month, Integer >();
public double getPrecipitationMonth( Month month ) {
return monthPrecipitation.get( month );
}
I would write eum something like that:
public enum Month {
JAN (1.0),
FEB (2.0),
MAR (3.0);
private double mId;
public static Month fromDoubleToEnum( double value ) throws Exception{
for ( Month c : Month.values() ) {
if ( c.mId == value ) {
return c;
}
}
throw new Exception( "Illegal Month value: " + value );
}
public double fromEnumToDouble(){
return mId;
}
private EModule (double num){
mId = num;
}
}
Here we have method: fromEnumToDouble that returns double on enum.
Test
public static void main(String[] args) {
Month mod = Month.FEB;
double toDouble = mod.fromEnumToDouble();
System.out.println(toDouble); // out 2.0
}
Use an EnumMap to store your precipitationMonths array instead.
EnumMap<Month,Something> precipitationMonths = new EnumMap<Month,Something>(Month.class);
precipitationMonths.put(Month.JANUARY, someValue); // Add a value
Something someValue = precipitationMonths.get(Month.JANUARY); // Get a value
Regarding that your data are located in file you need to create a class that will store that data and be able to map them.
The Java has really poor support for calendar, but you can work with it using Calendar class
You can create a enum for calendar but it is not mandatory.
enum Month{
JANUARY(Calender.JANUARY);
private final int month;
Month(int month) {
this.month = month;
}
public int month() {
return month;
}
}
When you solve the first problem of matching the data from file with months.
private final Map<Month,Double> precipitationMap = new EnumMap<>();
private void assignPrecipitation(Month month, double precipitation) {
this.precipitationMap.put(month,precipitation);
}
public double getPrecipitation(Month month) {
if(this.precipitationMap.contains(month) {
return this.precipitationMap.get(month).doubleValue();
}
throw new IllegalStateException("The Precipitation was not found for: " + myCalendar);
}
I'm playing around with arrays and enums and i was wondering whats the most effect way to create a Comparator class to sort these dates in descending order. Heres my code.
public enum Month {JAN(1), FEB(2), MAR(3), APR(4), MAY(5), JUN(6), JUL(7),
AUG(8), SEPT(9), OCT(10), NOV(11), DEC(12);
final int monthBoundary;
Month(int y){
monthBoundary=y;}
}
public enum Date {FIRST(1), SECOND(2), THIRD(3), FORTH(4),
FIFTH(5)... THIRTYFIRST(31);
final int dateBoundary;
Date(int z){
dateBoundary=z;}
}
//constructor etc here
private static final List<Cal> calendar = new ArrayList<Cal>();
static {
for (Month month : Month.values()) {
for (Date date : Date.values()) {
calendar.add(new Cal(date, month));
}
}
}
//creates new calendar dates
public static ArrayList<Cal> newCal() {
return new ArrayList<Cal>(calendar);
}
Using the following statement i can print the array in the order its created.
System.out.print(Card.calendar());
How do you create a Comparator class to sort these dates in descending order?
Ideally i would like it to sort the array whether it was already in order or in a random order.
At this stage i am not concerned about dates that do not exist (e.g. Feb 31st) as i'm merely practising and self studying... Just trying to get the concept :)
Thanks.
ADDED:
public ArrayList<Cal> sortDescending(ArrayList<Cal> calList){
Comparator<Cal> c = Collections.reverseOrder();
Collections.sort(calList, c);
return calList;
}
Collections.sort(list, new Comparator<Cal>() {
#Override
public int compare(Cal cal1, Cal cal2) {
int result = -cal1.getMonth().compareTo(cal2.getMonth()));
if (result == 0) {
result = -cal1.getDate().compareTo(cal2.getDate()));
}
return result;
}
});
I have a list of strings, each one contains time like this:
"03:00 AM", "12:30 PM", "16:15"
I need to sort them in order: put "am" times first and compare hours, not just first digits in a string.
This works for groovy, with all cases you gave:
List dates = [ "16:15", "12:30 PM", "07:00", "03:00 AM" ]
dates.sort { d ->
[ 'h:mm a', 'H:mm' ].findResult { fmt ->
try {
Date.parse( fmt, d ).time
} catch( e ) {}
}
}
It basically tries with AM/PM and then tries without it if that fails
Use the SimpleDateFormat class to determine the time which represents each string and then compare that numeric value when sorting. It looks like the time strings you're dealing with can have different kinds of formats, so I've edited the answer to support strings of format 03:00AM or 16:23
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class TimeStringComparator implements Comparator<String>{
private DateFormat primaryFormat = new SimpleDateFormat("h:mm a");
private DateFormat secondaryFormat = new SimpleDateFormat("H:mm");
#Override
public int compare(String time1, String time2){
return timeInMillis(time1) - timeInMillis(time2);
}
public int timeInMillis(String time){
return timeInMillis(time, primaryFormat);
}
private int timeInMillis(String time, DateFormat format) {
// you may need more advanced logic here when parsing the time if some times have am/pm and others don't.
try{
Date date = format.parse(time);
return (int)date.getTime();
}catch(ParseException e){
if(format != secondaryFormat){
return timeInMillis(time, secondaryFormat);
}else{
throw e;
}
}
}
public static void main(String[] args){
List<String> times = Arrays.asList(new String[]{"03:00 AM", "12:30 PM", "16:15"});
Collections.sort(times, new TimeStringComparator());
System.out.println(times);
}
}
All of Java's sorting machinery -- for example, the Collections.sort() methods -- work with (or can work with) a comparator -- an instance of a class you write yourself that implements java.util.Comparator. That interface has a compare() method, and you can implement it to do any kind of comparison you want. That's what you'll need to do here.
As #Ernest said, you need to use a Comparator. You can do something like this with your list:
List<String> times;
Collections.sort(times, new Comparator<String>() {
#Override
public int compare(String time1, String time2) {
// Sorting implementation here
}
});