Reputation: 179
I put the ints that I made for the Month, Day, and Year together using the toString method. and then brought it to the main program.
public class Dog
{
private String dogName;
private int dogMonth;
private int dogDay;
private int dogYear;
public Dog(String name, int month, int day, int year)
{
dogName = name;
dogMonth = month;
dogDay = day;
dogYear = year;
}
public String getName()
{
return dogName;
}
public String toString()
{
return String.format("%d/%d/%d", dogMonth, dogDay, dogYear);
}
Then I tried to find which is the lowest. but I don't know if I need a calendar API.
while(sc.hasNextLine())
{
// read a line from the input file via sc into line
line = sc.nextLine();
StringTokenizer stk = new StringTokenizer(line);
String name = stk.nextToken();
int month = Integer.parseInt(stk.nextToken());
int day = Integer.parseInt(stk.nextToken());
int year = Integer.parseInt(stk.nextToken());
Dog list = new Dog(name, month, day, year);
dogs.add(list);
}
sc.close();
String lowDate= dogs.get(0).toString();
String lowName = dogs.get(0).getName();
for (int i = 0; i< dogs.size(); i++)
{
String newLow= dogs.get(i).toString();
String newName = dogs.get(i).getName();
if(lowDate>newLow)
{
lowDate = newLow;
lowName= newName;
}
System.out.println("The youngest dog is"+lowName+lowDate);
How would I figure out the youngest and oldest?
For example:
File:
Dog#1 12 25 2005
Dog#2 7 15 2003
Dog#3 9 24 2005
Dog#4 1 1 2001
Outcome:
The oldest is Dog#4 1/1/2001
The youngest is Dog#1 12/25/2005
Upvotes: 2
Views: 3099
Reputation: 338326
To represent a date-only value, without time-of-day, and without time zone, use java.time.LocalDate
class. Make that class the type of the birth date field on the Dog
class.
If the purpose of your class is to transparently communicate shallowly-immutable data, define the class as record.
Here is your entire Dog
class, just one short line.
record Dog ( String name , LocalDate birthDate ) {}
After collecting year-month-day input from the user, instantiate a LocalDate
. Pass to the constructor of your Dog
class.
final List < Dog > dogs = new ArrayList <> () ;
…
dogs.add ( new Dog ( "Fido" , LocalDate.of ( y , m , d ) ) ) ;
The LocalDate
objects know how to sort themselves. Pass a Comparator
to specify using the birthDate
field.
dogs.sort ( Comparator.comparing ( Dog :: birthDate ) );
Full example:
final List < Dog > dogs = new ArrayList <> ( );
dogs.add ( new Dog ( "Fido" , LocalDate.of ( 2024 , Month.FEBRUARY , 24 ) ) );
dogs.add ( new Dog ( "Alfy" , LocalDate.of ( 2020 , Month.MARCH , 20 ) ) );
dogs.add ( new Dog ( "Fluffy" , LocalDate.of ( 2022 , Month.APRIL , 22 ) ) );
dogs.sort ( Comparator.comparing ( Dog :: birthDate ) );
Report each dog with its calculated age.
LocalDate today = LocalDate.now ( ZoneId.of ( "America/Edmonton" ) );
dogs.forEach ( dog -> System.out.println ( "Dog: " + dog.name ( ) + " Age: " + Period.between ( dog.birthDate ( ) , today ) ) );
When run:
Dog: Alfy Age: P4Y9M19D
Dog: Fluffy Age: P2Y8M17D
Dog: Fido Age: P10M15D
You asked for the oldest and youngest dogs. To find those, ask for the first and last elements of the sorted list.
System.out.println ( "Oldest: " + dogs.getFirst ( ) );
System.out.println ( "Youngest: " + dogs.getLast ( ) );
When run:
Oldest: Dog[name=Alfy, birthDate=2020-03-20]
Youngest: Dog[name=Fido, birthDate=2024-02-24]
This code ignores ties, when two or more dogs are born on the same day. To handle that, to report multiple oldest or youngest dogs, you’d need another approach. For example, a multimap of birthdate to collection of dogs sharing that date.
Upvotes: 1
Reputation: 338326
Yes, if you are working with date-time data you should use date-time types (classes).
java.util.Date
Unfortunately, the old date-time clases bundled with Java (java.util.Date, .Calendar, and so on) are notoriously troublesome. Avoid them. Among many other problems, they lack a way to represent a date-only without time-of-day and time zone which is what you need.
Instead use either the Joda-Time library or the java.time package bundled with Java 8 (inspired by Joda-Time).
As described in other answers, we must implement a comparator to reach inside the Dog object to retrieve and then compare his/her birthdate.
To actually compare the birthdates, we call the LocalDate comparison methods: isBefore
, isAfter
, and isEqual
.
Like java.time, Joda-Time includes a LocalDate
class to represent date-only values without any time-of-day nor time zone.
Here is some example code in Joda-Time 2.4.
package com.example.jodatimeexperiment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.joda.time.LocalDate;
public class Dog
{
// Member variables.
String name = null;
LocalDate birthDate = null;
// Constructor
public Dog( String nameArg , int yearArg , int monthArg , int dayOfMonthArg )
{
this.name = nameArg;
this.birthDate = new LocalDate( yearArg , monthArg , dayOfMonthArg );
}
@Override
public String toString()
{
return "Dog{" + "name=" + name + ", birthDate=" + birthDate + '}';
}
// Main method, to run this program.
public static void main( String[] args )
{
List<Dog> list = new ArrayList<>();
list.add( new Dog( "Alpha" , 2005 , 12 , 25 ) );
list.add( new Dog( "Beta" , 2003 , 7 , 15 ) );
list.add( new Dog( "Gamma" , 2005 , 9 , 24 ) );
list.add( new Dog( "Delta" , 2001 , 1 , 1 ) );
Collections.sort( list , new AgeComparator() );
System.out.println( "Oldest: " + list.get( 0 ) ); // First item in list.
System.out.println( "Youngest: " + list.get( list.size() - 1 ) ); // Last item in list.
}
}
// Implement a Comparator.
class AgeComparator implements Comparator<Dog>
{
@Override
public int compare( Dog dog1 , Dog dog2 )
{
if ( dog1.birthDate.isAfter( dog2.birthDate ) ) {
return 1;
} else if ( dog1.birthDate.isBefore( dog2.birthDate ) ) {
return -1;
} else if ( dog1.birthDate.isEqual( dog2.birthDate ) ) {
return 0;
} else {
// FIXME: Handle this supposedly impossible error condition.
// Programmer made a mistake in logic or a typo in comparisons above.
return -1; // Arbitrary choice of value to satisfy compiler.
}
}
}
When run.
Oldest: Dog{name=Delta, birthDate=2001-01-01}
Youngest: Dog{name=Alpha, birthDate=2005-12-25}
Probably not a part of your homework assignment, but FYI, the example code above assumes all the birthdate data represents the same time zone. If the birthdates are not representative of the same time zone, ideally you would pass in a time zone or offset from UTC.
Upvotes: 0
Reputation: 3541
I suggest you use a Comparer to sort a collection of dogs. Have a look at the javadoc of java.util.Comparator and java.lang.Comparable
The integers dogDay, dogMonth and dogYear are parts of the representation of a single concept, the dog's birthday. So instead of letting the dog have those three integers separately, I would advise you to define a date-like class that contains those.
class Dog {
String dogName;
Date dogBirthday;
Now, you can define an ordering on your date-like class. You can do this by implementing the Comparable interface.
class Date implements Comparable<Date> {
final int day;
final int month;
final int year;
public Date(int day, int month, int year) {
/* could check for invalid dates, e.g.,
if (day < 1 || day > 31 || month < 1 || ...) {
throw new InvalidArgumentException("Invalid date");
} */
this.day = day; this.month = month; this.year = year;
}
public int compareTo(Date other) {
// Dates are comparable in lexicographic order
int result = Integer(year).compareTo(Integer(other.year);
if (result == 0) { result = Integer(month).compareTo(Integer(other.month)); }
if (result == 0) { result = Integer(day).compareTo(Integer(other.day)); }
return result;
}
}
Having an ordering on dates, you can sort a collection of dogs by their birhtday.
Collections.sort(dogs,
new Comparator<Dog>{
int compare(Dog d1, Dog d2) { return d1.dogBirthday.compareTo(d2.dogBirthday);}
};)
Note that if you intend to implement Comparable, you should also override java.lang.Object's equals and hashCode method (though, you are not bound by contract to do so).
A side note on the Date class I defined: It is always good to reuse existing code, so definig your own Date class may not be the best thing to do. However, I would advise you not to use java.util.Date, as this class is completely broken. If I am not mistaken, one of its main issues is that it is mutable, which is basically as bad as having String being mutable: You would need to make a lot of defensive copies or your code may break in potentially hard to debug ways. If you intent to make more extensive use of dates and you are using Java 8, then use the new Date and Time library. If you are using an older version of Java, I suggest you have a look at Joda time.
Upvotes: 2
Reputation: 1103
1. add field Calendar to your dog class to replace the month,day,year field
2. use Calendar.setTime(Date )to initiate
3. use Calendar.after or Calendar.before to compare
Upvotes: 0
Reputation: 15755
Normally, I would recommend to always use a calender when working with dates. This is because dates get complicated really fast, like the 29th of February. However for this specific case, you dont need a calender API.
The problem you have currently is you are converting the dates to Strings, then comparing the strings. DONT DO THIS. Comparing strings is bad (it actually doesnt work the way you would expect).
You already have the numbers, so why dont you use them. Just put getter methods for month, day, and year in your dog class.
Then all you need to compare the dogs is a simple "find the smallest number" method. Find the smallest of the year. If that doesnt work, then than the month, if that doesnt work, than the day.
public Dog youngestDog(List<Dog> dogs) {
youngest = new Dog("Fake", 12, 31, 9999);
for (dog : dogs) {
if (dog.getYear() < youngest.getYear()) {
youngest = dog;
}
else if (dog.getYear() == youngest.getYear()) {
if (dog.getMonth() < youngest.getMonth()) {
youngest = dog;
}
if (dog.getMonth() == youngest.getMonth()) {
if (dog.getDay() <= youngest.getDay()) {
youngest = dog;
}
}
}
}
return youngest;
}
Note: Ideally you would actually want to use a comparator or implement comparable, but that is more advanced and probably way beyond what you are trying to learn.
Upvotes: 1
Reputation: 25409
You could use a calendar / date function from the standard library. But it turns out that your question can also be answered easily without it:
Upvotes: 2