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;
}
});
Related
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.
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 have class (JavaBean if you want to call it like that)
class Tweet{
private millis; //number of millis since 1970
//other attributes and getters and setters, but i want to sort onlny by millis
public long getMillis() {
return millis;
}
}
Comparator should be probably look simillar to this:
class TweetComparator implements Comparator {
#Override
public int compare(Tweet t1, Tweet t2) {
//something
//this doesn't work
//return t2.getMillis().compareTo(t1.getMillis());
return ??;//what should be here?
}
}
This will be in program
List<Tweet> tweets = new ArrayList<Tweet>();
tweets.add(...); //just fill the list
//i need newest (with hightest millis value first) so I probably need to call reverse order
Collection.reverse(tweets)
Collection.sort(tweets, new TweetComparator());
I found some references here
and here. But I don't know how to complete my code.
Your comparator should look similar to this
class TweetComparator implements Comparator<Tweet> {
#Override
public int compare(Tweet t1, Tweet t2) {
return Long.compare(t1.getMillis(), t2.getMillis());
}
}
note that static int Long.compare is since Java 7
Compare method Returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, >or greater than the second.
Logic -
if t1.millis > t2.millis
return -1;
else if t1.millis < t2.millis
return +1;
Code -
class TweetComparator implements Comparator<Tweet> {
#Override
public int compare(Tweet t1, Tweet t2) {
if(s1.i>s2.i)
return -1;
else if(s1.i<s2.i)
return +1;
return 0;
}
}
Try This:
#Override
public int compare(Tweet t1, Tweet t2) {
return t1.getMillis().compareTo(t2.getMillis());
}
Change you mills varaible to Long if you want to use inbuilt compareTo method of Long class.
Otherwise inside compare method,compare your millis from t1 and t2 like below.
long t1Val = t1.getMillis();
long t2Val = t2.getMillis();
return (t1Val<t2Val? -1 : (t1Val ==t2Val? 0 : 1));
(Directly from original Long class)
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
}
});