I was wondering if anyone could look over a class I wrote, I am receiving generic warnings in Eclipse and I am just wondering if it could be cleaned up at all. All of the warnings I received are surrounded in ** in my code below.
The class takes a list of strings in the form of (hh:mm AM/PM) and converts them into HourMinute objects in order to find the first time in the list that comes after the current time.
I am also curious about if there are more efficient ways to do this. This works fine but the student in me just wants to find out how I could do this better.
public class FindTime {
private String[] hourMinuteStringArray;
public FindTime(String[] hourMinuteStringArray){
this.hourMinuteStringArray = hourMinuteStringArray;
}
public int findTime(){
HourMinuteList hourMinuteList = convertHMStringArrayToHMArray(hourMinuteStringArray);
Calendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
HourMinute now = new HourMinute(hour,minute);
int nearestTimeIndex = findNearestTimeIndex(hourMinuteList, now);
return nearestTimeIndex;
}
private int findNearestTimeIndex(HourMinuteList hourMinuteList, HourMinute now){
HourMinute current;
int position = 0;
Iterator<HourMinute> iterator = **hourMinuteList.iterator()**;
while(iterator.hasNext()){
current = (HourMinute) iterator.next();
if(now.compareTo(current) == -1){
return position;
}
position++;
}
return position;
}
private static HourMinuteList convertHMStringArrayToHMArray(String[] times){
FindTime s = new FindTime(new String[1]);
HourMinuteList list = s.new HourMinuteList();
String[] splitTime = new String[3];
for(String time : times ){
String[] tempFirst = time.split(":");
String[] tempSecond = tempFirst[1].split(" ");
splitTime[0] = tempFirst[0];
splitTime[1] = tempSecond[0];
splitTime[2] = tempSecond[1];
int hour = Integer.parseInt(splitTime[0]);
int minute = Integer.parseInt(splitTime[1]);
HourMinute hm;
if(splitTime[2] == "AM"){
hm = s.new HourMinute(hour,minute);
}
else if((splitTime[2].equals("PM")) && (hour < 12)){
hm = s.new HourMinute(hour + 12,minute);
}
else{
hm = s.new HourMinute(hour,minute);
}
**list.add(hm);**
}
return list;
}
class **HourMinuteList** extends **ArrayList** implements RandomAccess{
}
class HourMinute implements **Comparable** {
int hour;
int minute;
public HourMinute(int hour, int minute) {
setHour(hour);
setMinute(minute);
}
int getMinute() {
return this.minute;
}
String getMinuteString(){
if(this.minute < 10){
return "0" + this.minute;
}else{
return "" + this.minute;
}
}
int getHour() {
return this.hour;
}
void setHour(int hour) {
this.hour = hour;
}
void setMinute(int minute) {
this.minute = minute;
}
#Override
public int compareTo(Object aThat) {
if (aThat instanceof HourMinute) {
HourMinute that = (HourMinute) aThat;
if (this.getHour() == that.getHour()) {
if (this.getMinute() > that.getMinute()) {
return 1;
} else if (this.getMinute() < that.getMinute()) {
return -1;
} else {
return 0;
}
} else if (this.getHour() > that.getHour()) {
return 1;
} else if (this.getHour() < that.getHour()) {
return -1;
} else {
return 0;
}
}
return 0;
}
}
If you have any questions let me know.
Thanks,
Rob
It's because you a not specify generics for your List and Comparable instances, that can support generics. You can rewrite your code with:
class HourMinuteList extends ArrayList<HourMinute> implements RandomAccess{
}
class HourMinute implements Comparable<HourMinute> {
public int compareTo(HourMinute aThat) {
....
}
}
Note: generics is not required, and not used at runtime, but it's better to use them because it helps you to avoid some bugs at your code.
I wouldn't use the HourMinute class, unless it has some other added value. If you only need to find the closest event time after a given point in time, convert your strings to Date (or to long values representing time), and store them in some sorted collection.
The conversion can be done with SimpleDateFormat.
If items are added dynamically, use TreeSet<Date>, together with ceiling(t) / higher(t) methods.
If the set of items is not dynamic, use an array Date[], together with Arrays.binarySearch(..).
Here is a (working) draft of the first approach:
public class TimedEventsMgr {
private TreeSet<Date> pointsInTime = new TreeSet<Date>();
private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hh:mm a");
//timeStr: hh:mm AM/PM
public void add(String timeStr) throws ParseException{
Date time = sdf.parse("20000101 "+timeStr);
pointsInTime.add(time);
}
public Date closestFutureTime(Date time){
Calendar c = Calendar.getInstance();
c.setTime(time);
c.set(Calendar.YEAR, 2000);
c.set(Calendar.MONTH, 0); //January
c.set(Calendar.DATE, 1);
return pointsInTime.higher(c.getTime());
}
}
Related
First of all, I have read this question which i am aware is dealing with the same fundamental problem I am having.
Nevertheless, I am unable to apply the solution to my own particular problem.
in the following example i have a few overloaded Clock constructors. The error occurs in the case where I am trying to create a Clock from string input.
Does anyone have any tips for the correct implementation of the constructor call?
Code:
public class Clock
{
public static void main(String[] args)
{
Clock testClock = new Clock(153, 26);
System.out.println("Input: Clock(153, 26)");
System.out.println(testClock.toString());
Clock testClock2 = new Clock(9000);
System.out.println("Input: Clock(9000)");
System.out.println(testClock2.toString());
Clock testClock3 = new Clock(23:59);
System.out.println("Input: Clock(23:59)");
System.out.println(testClock3.toString());
System.out.println("Input: testClock2.add(20)");
System.out.println(testClock2.add(20));
System.out.println("input: testClock.add(testClock2)");
System.out.println(testClock.add(testClock2).toString());
}
// Constructors
public Clock(int min, int h)
{
this.min += min%60;
h += min/60;
this.h += h%24;
}
public Clock(int min)
{
this.min += min%60;
this.h += (min/60)%24;
}
public Clock (String theTime)
{
int minutes = Integer.parseInt(theTime.substring(0,1));
int hours = Integer.parseInt(theTime.substring(3,4));
Clock stringClock = new Clock(minutes, hours);
return stringClock; //error occurs *********************
}
private int h;
private int min;
public int getMin() {
return min;
}
public int getH() {
return h;
}
public Clock add(int min)
{
int newMin = this.min + min;
int newH = this.h;
Clock newClock = new Clock(newMin, newH);
return newClock;
}
public Clock add(Clock c)
{
int newMin = this.min + c.min;
int newH = this.h + c.h;
Clock newClock = new Clock(newMin, newH);
return newClock;
}
public String toString()
{
String theTime = "";
if (this.h < 10)
{
theTime += "0" + this.h;
}
else
{
theTime += this.h;
}
theTime += ":";
if (this.min < 10)
{
theTime += "0" + this.min;
}
else
{
theTime += this.min;
}
return theTime;
}
}
You could call this but it should be very first statement such as:
public Clock (String theTime)
{
this(
Integer.parseInt(theTime.substring(0,1)),
Integer.parseInt(theTime.substring(3,4))
);
}
Alternatively you could use a static factory method:
public static Clock parseHHMM(String theTime)
{
int hh = Integer.parseInt(theTime.substring(0,1));
int mm = Integer.parseInt(theTime.substring(3,4));
return new Clock(hh, mm);
}
I prefer the latter, it is common approach in Java, e.g. here.
There is also a problem with that line:
Clock testClock3 = new Clock(23:59);
If you want the argument to be treated as String, you should surround the value passed as argument with quotes, like this:
Clock testClock3 = new Clock("23:59");
, because when you don't change the look of parameter passed, it won't compile.
You could consider splitting theTime at the semicolon":" so as to obtain an array of two integers, the first being the hour and the second being the minutes. Take a look
public Clock (String theTime)
{
this(Integer.parseInt(theTime.split(":")[1],
Integer.parseInt(theTime.split(":")[0]);
}
hope this helps
I have to implement an interface and try it out in two different classes one with Array and one with List. In these classes we have to add different methods as seen in the interface ->
public interface IStatistics {
public void addSample(String name, GregorianCalendar date, double value);
public double getMeanTemperature(int month);
public double getMedianTemperature(int month);
public double getVariance(int month);
public double getStandardDeviation(int month);
public void printSamples(int month);
}
I've already done most of it but it should only use the values from a specific month which doesn't work in both methods. In this exercise we get a certain value every day for one year(name, date, temperature). I don't know how to get it to only use the values from one month(which doesn't work in both classes) In the List I already tried it out but it doesn't work at all.
#Override
public double getMeanTemperature(int month) {
MeasurementValue m = this.head;
double result = 0;
while(m.date.get(GregorianCalendar.MONTH)==month){
while(m!=null){
result = result + m.temp;
m=m.getNext();
}
result = result/this.num;
}
return result;
}
And in the class with Array I don't even know how to start.
#Override
public double getMeanTemperature(int month) {
double sum = 0.0;
for(double a : values)
sum += a;
return sum/numValues;
}
Also it doesn't print out the dates correctly. Maybe anyone knows a solution for that.
import java.util.GregorianCalendar;
import kwm.statistics.IStatistics;
import kwm.statistics.MeasurementArray;
import kwm.statistics.MeasurementList;
public class TestStatistics {
public static void main(String[] args) {
GregorianCalendar date = new GregorianCalendar(2017,05,12);
GregorianCalendar date1 = new GregorianCalendar(2017,05,02);
GregorianCalendar date2 = new GregorianCalendar(2017,05,22);
GregorianCalendar date3 = new GregorianCalendar(2017,06,06);
GregorianCalendar date4 = new GregorianCalendar(2017,05,18);
// ***TESTLIST***
IStatistics statistics1 = new MeasurementList();
statistics1.addSample("Lisa", date, 12);
statistics1.addSample("Lisa", date1, 17);
statistics1.addSample("Lisa", date2, 14);
statistics1.printSamples(5);
// ***TESTARRAY***
IStatistics statistics2 = new MeasurementArray();
statistics2.addSample("Lisa", date, 12);
statistics2.addSample("Lisa", date1, 5);
statistics2.addSample("Lisa", date2, 40);
statistics2.addSample("Lisa", date3, 31);
statistics2.addSample("Lisa", date4, 23);
statistics2.printSamples(5);
}
}
That's the code for the output in MeasurementValue
public void output(){
GregorianCalendar date = this.date;
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
System.out.print(sdf.format(date.getTime()));
}
And the code for the output in MeasurementList.
public void printSamples(int month) {
MeasurementValue m = this.head;
// while(m.date.get(GregorianCalendar.MONTH)==month){
while(m != null){
if(month>=0 && 11>=month){
System.out.println("Name: "+m.getName());
System.out.println("Value: "+m.getTemp());
System.out.print("Date: ");m.output();
System.out.print("\n");
System.out.print("*****************\n\n");
m = m.getNext();
}
}
// }
System.out.print("\n");
}
Thanks for any help!
For the linked list version, try something like this:
#Override
public double getMeanTemperature(int month) {
double total = 0d;
int num = 0;
for (MeasurementValue m = this.head; m != null; m = m.getNext()) {
if (m.date.get(Calendar.MONTH) == month) {
total += m.temp;
num++;
}
}
if (num == 0) {
// Avoid division by zero
return 0d;
}
return total / (double) num;
}
Same principle for the array but you iterate differently (and you need to store the months as well).
I am trying my hands on this questions:https://www.codeeval.com/browse/214/ and below is my code and ouput:
CODE
public class TimeSort implements Comparable<TimeSort>{
public int hour;
public int minutes;
public int seconds;
public TimeSort(int hour, int minutes, int seconds) {
this.hour = hour;
this.minutes = minutes;
this.seconds = seconds;
}
public TimeSort(String str){
/*DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
final String x = str;
try {
Date time = sdf.parse(x);
//Time time = new Time(new SimpleDateFormat("HH:mm:ss").parse(x).getTime());
this.hour = time.getHours();
this.minutes = time.getMinutes();
this.seconds = time.getSeconds();
} catch (ParseException e) {
e.printStackTrace();
}*/
String[] parts = str.split(":");
int hour = Integer.parseInt(parts[0]);
int minutes = Integer.parseInt(parts[1]);
int seconds = Integer.parseInt(parts[2]);
this.hour = hour;
this.minutes = minutes;
this.seconds = seconds;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getMinutes() {
return minutes;
}
public void setMinutes(int minutes) {
this.minutes = minutes;
}
public int getSeconds() {
return seconds;
}
public void setSeconds(int seconds) {
this.seconds = seconds;
}
#Override
public String toString() {
if(this.getHour() < 10){
return "0"+this.getHour()+":"+this.getSeconds()+":"+this.getSeconds();
}
return this.getHour()+":"+this.getSeconds()+":"+this.getSeconds();
}
public static void main(String[] args){
List<String> inputs = new ArrayList<>();
inputs.add("02:26:31 14:44:45 09:53:27");
inputs.add("05:33:44 21:25:41");
inputs.add("02:26:31 14:44:45 09:53:27 02:26:31 01:44:45 19:53:27");
for (String input : inputs){
sortTimes(input);
}
}
#Override
public int compareTo(TimeSort timeSort) {
if(this.getHour() > timeSort.getHour()){
return -1;
}
else if(this.getHour() < timeSort.getHour()){
return 1;
}
else if(this.getHour() == timeSort.getHour()) {
if(this.getMinutes() > timeSort.getMinutes()){
return -1;
}
else if(this.getMinutes() < timeSort.getMinutes()){
return 1;
}
}
else if(this.getSeconds() > timeSort.getSeconds()){
return 1;
}
return 0;
}
public static void sortTimes(String str){
List<TimeSort> list = new ArrayList<>();
String[] times = str.split(" ");
for (String time : times){
list.add(new TimeSort(time));
}
System.out.print("Before Sorting: ");
for (TimeSort t : list){
System.out.print(t + " ");
}
System.out.println();
Collections.sort(list);
System.out.print("After Sorting: ");
for (TimeSort t : list){
System.out.print(t + " ");
}
System.out.println();
System.out.println("==============================================================");
}
}
OUTPUT
Before Sorting: 02:31:31 14:45:45 09:27:27
After Sorting: 14:45:45 09:27:27 02:31:31
==============================================================
Before Sorting: 05:44:44 21:41:41
After Sorting: 21:41:41 05:44:44
==============================================================
Before Sorting: 02:31:31 14:45:45 09:27:27 02:31:31 01:45:45 19:27:27
After Sorting: 19:27:27 14:45:45 09:27:27 02:31:31 02:31:31 01:45:45
==============================================================
The weird thing I am seeing is the times do not print correctly. For example 02:26:31 is print as 02:31:31. And it's the same even if I tried to parse the string time(commented part of the code)
Any help is appreciated. Thanks
Your toString() method has a bug:
#Override
public String toString() {
if(this.getHour() < 10){
return "0"+this.getHour()+":"+this.getSeconds()+":"+this.getSeconds();
}
return this.getHour()+":"+this.getSeconds()+":"+this.getSeconds();
}
Note that the 2nd field is getSeconds() instead of getMinutes().
Your toString()-method does not print the minutes!
The other Answers found the bug in your code.
java.time
FYI, all of that code in unnecessary. Java 8 and later has the java.time framework built-in. Amongst its classes is LocalTime for representing a time-of-day-only value without a date and without a time zone. This class already knows how to compare and sort its values and how to parse/print its values. Printing follows standard ISO 8601 formats by default.
List<LocalTime> times = new ArrayList<>();
times.add( LocalTime.parse( "02:26:31" );
times.add( LocalTime.parse( "14:44:45" );
times.add( LocalTime.parse( "09:53:27" );
Collections.sort( times );
Dump to console.
System.out.println( times );
I have an Event class which uses the PriorityQueue and a Time class that I defined myself to use with the Event class.
static class Event implements Comparable<Event>{
Customer customer;
Time eventTime;
char eventType;
public int compareTo(Event e){
int n = e.eventTime.compareTo(eventTime);
int compare = 0;
if(n < 0){
compare = -1;
}
else if(n == 0){
compare = 0;
}
else if(n > 0){
compare = 1;
}
return compare;
}
}
class Time{
private int hour;
private int minute;
private boolean isMorning;
public Time(){
hour = 0;
minute = 0;
isMorning = true;
}
public Time(int h, int m, boolean morning){
hour = h;
minute = m;
isMorning = morning;
}
public void setTime(int h, int m, boolean morning){
hour = h;
minute = m;
isMorning = morning;
}
public int getHour(){
return hour;
}
public int getMinute(){
return minute;
}
public boolean isAM(){
return isMorning;
}
public String toString(){
String AM = "";
String min = "";
if(minute < 10){
min = ("0" + minute);
}
else{
min = ("" + minute);
}
if(isMorning){
AM = "AM";
}
else{
AM = "PM";
}
return ("" + hour + ":" + min + " " + AM);
}
public Time plus(int n){
Time newTime = new Time();
boolean newMorning = false;
int minutes = minute + n;
int newHour = minutes/60;
int newMinutes = minutes%60;
hour = hour + newHour;
if(hour > 12){
hour = hour - 12;
if(isMorning){
newMorning = false;
}
else{
newMorning = true;
}
}
newTime.setTime(hour, newMinutes, newMorning);
return newTime;
}
public int timeDifference(Time t){
int n = totalMinutes();
int m = t.totalMinutes();
return m - n;
}
public int compareTo(Time t){
int n = totalMinutes();
int m = t.totalMinutes();
int compare = 0;
if(n < m){
compare = -1;
}
else if(n == m){
compare = 0;
}
else if(n > m){
compare = 1;
}
return compare;
}
private int totalMinutes(){
int tempMinute = 0;
if(!isMorning){
if(hour == 12){
}
else{
hour = hour + 12;
tempMinute = (hour*60) + minute;
}
}
else{
if(hour == 12){
tempMinute = minute;
}
else{
tempMinute = (hour*60) + minute;
}
}
return tempMinute;
}
}
This isn't all of my code as I have others just holding the values that will later be inserted into the Event queue. When I check the time outside of the Event queue it matches the time that it should be, say I have a Time object as 11:22 AM, but when I insert it into the Event queue my time changes to 23:22 AM. For some reason it is adding 12 hours within the Event queue and I don't understand why.
Figured it out the totalMinutes() method was messing with the hours because it was being called when using compareTo() or timeDifference() implicitly. Thank you for the help!
First, totalMinutes() messes with the hour field when it shouldn't. It should use a local variable.
Second, your entire Event.compareTo(Event e) method can be reduced to
return e.eventTime.compareTo(eventTime);
which is back to front, unless you want the most recent times first. Try
return eventTime.compareTo(e.eventTime);
In my Java class, I have to build a calendar application. I've got it mostly completed, however I need help with a couple of methods. I have commented the parts that I need help with. The code includes three classes and a main called TestCalendar. The functions I need help with are located in the Calendar class, named removeEvent(two of them, taking two different arguments), printEvents, and findEvents. Thanks in advance!
Here is the Date class.
public class Date {
int year, month, day;
//constructor
public Date(int yr, int mth, int dy){
year = yr;
if (yr < 2000 || yr > 2100)
{
System.out.println("Wrong Calander Year");
System.exit(1);
}
month = mth;
if (mth < 1 || mth > 12)
{
System.out.println("Wrong Month");
System.exit(1);
}
day = dy;
if (dy < 1 || dy > 31)
{
System.out.println("Wrong Day");
System.exit(1);
}
}
//accessor methods
public int getYear()
{
return year;
}
public int getMonth()
{
return month;
}
public int getDay()
{
return day;
}
//returns date in correct format
public String toString()
{
return "" + month + "/" + day + "/" + year;
}
}
Here is the Event class
public class Event {
Date date;
int hour;
String activity;
Event(int year, int month, int day, int hour, String activity)
{
if (year < 2000 || year > 2100)
{
System.out.println("Wrong Calander Year");
System.exit(1);
}
if (month < 1 || month > 12)
{
System.out.println("Wrong Month");
System.exit(1);
}
if (day < 1 || day > 31)
{
System.out.println("Wrong Day");
System.exit(1);
}
this.date = new Date(year, month, day);
this.hour = hour;
this.activity = activity;
}
public Date getDate()
{
return date;
}
public int getHour()
{
return hour;
}
public String getActivity()
{
return activity;
}
void setActivity(String newActivity)
{
this.activity = newActivity;
}
public String toString()
{
return "" + date +" " + "#" + hour +":" + " " + activity;
}
public boolean equals(Object obj)
{
if (obj instanceof Event)
{
return true;
}
else return false;
}
}
The Calendar class
public class Calander {
static final int MAXEVENTS = 10;
Event[] events;
int numEvents;
// constructor
public Calander() {
numEvents = 0;
events = new Event[MAXEVENTS];
}
void addEvent(int year, int month, int day, int hour, String activity) {
Event newEvent = new Event(year, month, day, hour, activity);
events[numEvents] = newEvent;
numEvents++;
}
void removeEvent(int year, int month, int day, int hour, String activity) {
{
if (events[numEvents] == null);
numEvents--;
}
}
// instructions say to remove (all) Event objects in the Calendar that are equals to the event argument. Use the equals method from the event class
void removeEvent(Event event) {
//what to put here?
}
// this method needs to print every Event in the associated Calendar that matches the date arguments. Print each on a separate line, using the toString method from the Event class.
void printEvents(int year, int month, int day) { // how to set equality
if (this.events[numEvents] == )
{
// what to put here?
}
}
// same as above but matches the (Date date) arguments
void printEvents(Date date) {
toString();
}
// Return the first Event in the Calendar that has a matching (equals) activity field. If no match is found, you must return a reference type, so return null.
Event findEvent(String activity) {
//what to put here?
return null;
}
void dump() {
for (int i = 0; i < MAXEVENTS; i++)
{
if (events[i] != null)
System.out.println(events[i]);
}
}
}
well, your event class has a method:
public boolean equals(Object obj)
Which, presumably, should return whether or not the passed event is equal to the instance.
So your void removeEvent(Event event) method should look similar to the following:
take note that this is psudo-code and not valid java. you're going to have to flesh out the details on your own.
void removeEvent(Event event)
{
foreach(event e in this.events)
{
if(event.equals(e))
{
// remove e from the events array
}
}
}
The rest of the methods are going to more or less be similar in concept to the first one with 2 varying factorrs:
how you identify a match
what you do with the match
Since this is homework, I don't actually want to do your homework. So as a hint, you want to use (your event).equals(comparing to other event), not "==".