I have to sort an arraylist by the date and time entered by the user but for some reason the output comes out not in order
Below this code it the code im using to order
public int compareTo(Vehicle v){
int returnValue = 0;
if (this.parkDate.year> v.parkDate.getYear() &&
this.parkDate.month> v.parkDate.getMonth() &&
this.parkDate.day> v.parkDate.getDay() &&
this.parkDate.hours> v.parkDate.getHours() &&
this.parkDate.minuets> v.parkDate.getMinuets()){
returnValue = 1; }
else
returnValue = - 1;
return returnValue;
}
Your comparison logic isn't correct. You might perform your comparisons with Integer.compare(int, int) and return the result in the case of non-zero. Something like,
public int compareTo(Vehicle v) {
int returnValue = Integer.compare(this.parkDate.getYear(),
v.parkDate.getYear());
if (returnValue != 0) {
return returnValue;
}
returnValue = Integer.compare(this.parkDate.getMonth(),
v.parkDate.getMonth());
if (returnValue != 0) {
return returnValue;
}
returnValue = Integer.compare(this.parkDate.getDay(),
v.parkDate.getDay());
if (returnValue != 0) {
return returnValue;
}
returnValue = Integer.compare(this.parkDate.getHours(),
v.parkDate.getHours());
if (returnValue != 0) {
return returnValue;
}
return Integer.compare(this.parkDate.getMinuets(),
v.parkDate.getMinuets());
}
Or, you could shorten the above by using arrays and something like
int[] a = { this.parkDate.getYear(), this.parkDate.getMonth(),
this.parkDate.getDay(), this.parkDate.getHours(),
this.parkDate.getMinuets() };
int[] b = { v.parkDate.getYear(), v.parkDate.getMonth(),
v.parkDate.getDay(), v.parkDate.getHours(),
v.parkDate.getMinuets() };
for (int i = 0; i < a.length; i++) {
int rv = Integer.compare(a[i], b[i]);
if (rv != 0) {
return rv;
}
}
return 0;
Finally, I believe you want minutes not minuets.
The primary issue is your comparison logic. You are testing that your vehicle's park date's year is greater than the other vehicle's park date's year and your vehicle's park date's month is greater than the other vehicle's park date's month and ditto for the day, hour and minute. This is incorrect.
Consider 2016-01-01 00:00 and 2015-12-31 23:59. The former clearly comes after the latter, but its month, day, hour and minute are all less than the other. Your logic would therefore fail to produce the correct result in this instance.
A more suitable approach would be to:
compare the years: if they are different you can return a result, ie. less than or greater than
if they are the same, compare the months; if they are different you can return a result
if they are the same, compare the days; if they are different you can return a result
if they are the same, compare the hours; if they are different you can return a result
if they are the same, compare the minutes; if they are different you can return a result
if they are the same, indicate the dates are equal
(Also, make sure you remembered to implement Comparable on your Vehicle class.)
The reason is because you have an error in your boolean logic.
if (this.parkDate.year> v.parkDate.getYear() &&
this.parkDate.month> v.parkDate.getMonth() &&
this.parkDate.day> v.parkDate.getDay() &&
this.parkDate.hours> v.parkDate.getHours() &&
this.parkDate.minuets> v.parkDate.getMinuets()){
returnValue = 1; }
else
returnValue = - 1;
Else is like taking the negation of your if statement. In this case that equates to the following:
this.parkDate.year <= v.parkDate.getYear()
OR
this.parkDate.month <= v.parkDate.getMonth()
OR
this.parkDate.day> v.parkDate.getDay()
...
In other words
Negation(A && B) <=> (Negation(A) || Negation(B))
In the context of your situation, your else logic could be true even if the year is greater than this.parkDate
I think this should be enough to help you get it right. :)
i think you can use "compareTo" the result is 0, 1, -1
public int compareTo(Vehicle a, Vehicle b){
return a.parkDate.compareTo(b.parkDate);
}
Instead of storing the date and time as primitives, you can create a LocalDateTime and use it in Comparator
add field parkDate as LocalDateTime in Vehicle class
LocalDateTime parkDate = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second);
use the parkDate in compareTo method
#Override
public int compareTo(Vehicle o) {
return this.parkDate.compareTo(o.parkDate);
}
Related
public static boolean hasGreaterDoWhile(List<Integer> numbers, int number) {
int d = 0;
do {
if (numbers.get(d) > number){
return true;
}
d++;
}
while (d < numbers.size());
return false;
}
(JAVA only)
P.s This is a function i have tried, in order to check the first argument, and if it contains a number that is larger than the second argument, it will then return true, and flase otherwise.
Note that it is using do while loop. I just don't know which part of this code i have done wrong, because the system keeps telling me that "java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0".
Thank u, any hint will be much appriciated.
your list of Integers is empty. you can't access an index of an empty list:
public static boolean hasGreaterDoWhile(List<Integer> numbers, int number) {
int d = 0;
if (numbers.isEmpty()) return false;
do {
if (numbers.get(d) > number){
return true;
}
d++;
}
while (d < numbers.size());
return false;
}
A do-while control block works as follows:
Execute the do block
Check the condition. If it holds, return to (1)
Notice the order of this flow. Unlike a standard while, do-while will always execute one iteration before checking the condition. Therefore, for an empty list you will always try to access the 0-index element of the table, which does not exist, hence the error. You can use a while loop to avoid this:
public static boolean hasGreaterDoWhile(List<Integer> numbers, int number) {
int d = 0;
while (d < numbers.size()) {
if (numbers.get(d) > number){
return true;
}
d++;
}
return false;
}
You should check whether the collection is empty
like this
if(numbers == null || numbers.isEmpty()) {
return false;
}
int d = 0;
do {
if (numbers.get(d) > number){
return true;
}
d++;
}
while (d < numbers.size());
return false;
I'm trying to create a simple date class. My professor also wants us to include our own .equals method in the date class which should compare two objects. My problem is my method returns false unless I compare the exact same object, even if their values are the same.
Here is my driver:
public class Lab3Driver {
public static void main(String[] args) {
Date theDate = new Date(6, 30, 1995);
Date anotherDate = new Date(6, 30, 1995);
System.out.println(theDate.equals(anotherDate));
System.out.println(theDate);
System.out.println(anotherDate);
}
}
Here is my date class:
public class Date {
private int month;
private int day;
private int year;
public Date() // default no arg constructor
{
this.month = 1; // set to date I completed this class, for fun.
this.day = 26;
this.year = 2019;
}
public Date(int m, int d, int y) // normal constructor in case you want to initialize variables upon object declaration
{
this.month = m;
this.day = d;
this.year = y;
}
public int getMonth() {
return month;
}
public void setMonth(int month)
{
if (month >= 1 && month <= 12) // if else that checks and makes sure months are between 1 and 12
{
this.month = month;
}
else
{
System.out.println("Invalid month input. Months are between 1 and 12.");
}
}
public int getDay()
{
return day;
}
public void setDay(int day)
{
if (day >= 1 && day <= 31) // if else that checks and makes sure days are between 1 and 31
{
this.day = day;
}
else
{
System.out.println("Invalid day input. Days are between 1 and 31.");
}
}
public int getYear()
{
return year;
}
public void setYear(int year) // year can be set to anything, in the case that this program is used for something
{ // other than the present day, as in a reference to the past or future
this.year = year;
}
public String toString() // to string in order to print out the date that is stored
{
String theDate = "The date is: " + this.month + "/" + this.day + "/" + this.year;
return theDate;
}
public boolean equals(Object that) // compares two objects and checks for null/type casting
{
if (this == that)
return true;
else if(that == null || that.getClass()!= this.getClass())
{
System.out.println("Null or type casting of argument.");
return false;
}
else
return false;
}
Something with this method is creating a problem I think:
public boolean equals(Object that) // compares two objects and checks for null/type casting
{
if (this == that)
return true;
else if(that == null || that.getClass()!= this.getClass())
{
System.out.println("Null or type casting of argument.");
return false;
}
else
return false;
}
It's normal, because you wrote
else {
return false;
}
So whenever that object has a different reference and is from the same class you go in the else statement above which returns false.
You should implement the code instead of returning false, for example:
public boolean equals(Object that) // compares two objects and checks for null/type casting
{
if (this == that)
return true;
else if(that == null || that.getClass()!= this.getClass())
{
System.out.println("Null or type casting of argument.");
return false;
}
else
return this.year == that.getYear() && ...;
}
if (this == that)
This line does not compare the objects. This only verifies if your object is in the same memory space, basically asking if it is exactly the same object (pointing to the same place).
If you want to compare two different objects, two different instances like
Date theDate = new Date(6, 30, 1995);
Date anotherDate = new Date(6, 30, 1995);
then you'll have to add more lines of code that check each value in each variable in each of the objects, or override the ' == ' method to make it compare the values.
Sοme οther things tο nοte:
As Nate has already said, yοu have tο cοmpare the individual fields οf the twο οbjects yοu are cοmparing. Tο dο that, yοu can use return year == that.getYear() && day == that.getDay() && mοnth == that.getMοnth().
But wait! Yοur equals methοd takes in an Object. Therefοre, we can't use thοse methοds. There are twο ways yοu can fix this.
Dο an instanceοf check at the beginning οf the methοd, and then cast the parameter tο a Date οbject.
Restrict the parameter οf yοur methοd tο οnly allοw Date οbjects.
Persοnally, I wοuld dο the latter, since an errοr will pοp up at cοmpile time if yοu used a nοn-Date οbject. Hοwever, if yοu did a type check in methοd and thrοw an exceptiοn if the type check failed, yοu may never nοtice an errοr if yοu prοvided an argument that is nοt a Date οbject until the method is called.
One thing you need to make sure that if you override the equals method you should also override the hashCode method.
For your reference, please read the section
https://www.baeldung.com/java-equals-hashcode-contracts#hashcode
I have completed both the overridden methods for you.
#Override
public boolean equals(Object that) {
if (this == that)
return true;
if(!(that instanceof Date))
return false;
if(that == null || that.getClass()!= this.getClass())
return false;
Date anotherDate = (Date) that;
if(this.month == anotherDate.month
&& this.day == anotherDate.day
&& this.year == anotherDate.year)
return true;
return false;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (month ^ (month >>> 16));
result = prime * result + (int) (day ^ (day >>> 16));
result = prime * result + (int) (year ^ (year >>> 16));
return result;
}
I am trying to add objects into a Treeset but the objects not all are getting added.
class Fruits
{
String name ;
int weight;
int price;
Fruits(String n, int w, int p)
{
this.name=n;
this.weight=w;
this.price =p;
}
#Override
public int hashCode() {
System.out.println("hashcode called");
int prime =31;
int result =1;
result = prime*result +(this.name.hashCode()+this.price+this.weight);
return result;
}
#Override
public boolean equals(Object obj) {
System.out.println("Equals called");
if(null!=obj)
{
Fruits f= (Fruits) obj;
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
{
return true;
}
}
return false;
}
}
class FruitsComparator implements Comparator<Fruits>
{
//Order by Name, then quanity and then Price
#Override
public int compare(Fruits f1, Fruits f2)
{
if(f1.name.equals(f2.name) && f1.weight == f2.weight && f1.price == f2.price)
{
System.out.println(1);
return 0;
}
else if(f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price < f2.price)
{
System.out.println(2);
return -1;
}
else if (f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price > f2.price)
{
System.out.println(3);
return 1;
}
else if (f1.name.equals(f2.name) && f1.weight<f2.weight && f1.price == f2.price)
{
System.out.println(4);
return -1;
}
else if (f1.name.equals(f2.name) && f1.weight>f2.weight && f1.price == f2.price)
{
System.out.println(5);
return 1;
}
else if (f1.name.compareTo(f2.name) <1 && f1.weight==f2.weight && f1.price == f2.price)
{
System.out.println(6);
return -1;
}
else if (f1.name.compareTo(f2.name) >1 && f1.weight==f2.weight && f1.price == f2.price)
{
System.out.println(7);
return 1;
}
return 0;
}
}
From public static void main of another class.
Fruits f1= new Fruits("Apple",1,3);
Fruits f2= new Fruits("Apple",10,1);
Fruits f3= new Fruits("Apple",15,2);
Set<Fruits> sf = new TreeSet<Fruits>(new FruitsComparator());
sf.add(f1);
sf.add(f2);
sf.add(f3);
System.out.println("--Fruits Example--");
for( Fruits f: sf)
{
System.out.println(f.name+"-"+f.weight+"-"+f.price);
}
The output I get is :
--Fruits Example--
Apple-1-3
But when I have fruits objs as below i get the all the objects
just keeping everything same but the third element.
Fruits f1= new Fruits("Apple",1,3);
Fruits f2= new Fruits("Apple",1,1);
Fruits f3= new Fruits("Apple",1,2);
The output get for this is
--Fruits Example--
Apple-1-1
Apple-1-2
Apple-1-3
So somehow my objects are treated as same when I keep different elements on weight and price. I couldn't figure out as why the objects are treated as same. Please help.
The primary issue is, you are always checking two fields to be equal and only one to be different.
At the final else, that happens if at least 2 fields are different, you return 0 which means they should be treated as equal, and that is the reason you have this issue.
Since the order you want is to first sort by name, then by quantity and then by price, remove the && f1.price == f2.price from the 4th condition onwards, and remove && f1.weight==f2.weight on the last two.
You can avoid this issue completely if you use Java 8 style.
Set<Fruits> sf = new TreeSet<Fruits>(Comparator.comparing(Fruits::getName)
.thenComparing(Fruits::getWeight)
.thenComparing(Fruits::getPrice)
);
I have added the working code in codiva - online java compiler ide. I have also included a slightly cleaner implementation in FruitsComparator.java file.
Tree related collections don't use equals() or hashCode(). Those come into play for Map.
Your conditions in the compare result in a 0, hence the fruit isn't inserted.
First Apple goes in as the tree is empty. The 2nd & 3rd Apple result in false in all the if conditions, thus returning the final 0. Put a System.out.println() before the final return to confirm.
If you want to sort the fruits first by name, then by weight & then finally by price, here's a more compact way doing it:
#Override
public int compare(Fruits f1, Fruits f2) {
if (f1.name.equals(f2.name)) {
if (f1.weight < f2.weight) {
return -1;
} else if (f1.weight > f2.weight) {
return 1;
} else {
if (f1.price < f2.price) {
return -1;
} else if (f1.price > f2.price) {
return 1;
} else {
return 0;
}
}
} else {
return f1.name.compareTo(f2.name);
}
}
TreeSet, when used with a Comparator, the elements' equality is decided by the compare method of the Comparator, otherwise would use the compareTo method of its element since they are required to implement the Comparable interface. The hashcode and equals methods will only be used by the Set interface itself (such as method contains uses equals method to check if the elements are presented). And hashcode is not something that a TreeSet to use while it is used by HashSet which is totally another way to implement Set interface. Thus, in your code, since the compare method you've overridden of the Comparator treats these elements equal, so they cannot be inserted for multiple times. One guideline that the Java Tutorial points out is, the compare method should comply with the equals methods, which is, the elements should be treated equal in the compare method if and only if the equals method do.
And in your equals method, you did use this.weight == f.price to compare two fruits, which I don't think is what you intended to do. This makes your equals methods not consistent with the compare method.
For your reference, see Java Object Ordering tutorial, and as well as a question I asked two days ago.
You have an error in your equals method in class Fruits:
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
should have been:
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.weight)
(note the last part).
I'n my application i want to sort the "MyDate" class so, my teacher show me how to sort but how can i compare years first and then the rest?
Comparator<MyDate > dateCompare = new Comparator<MyDate >() {
#Override
public int compare(MyDate o1, MyDate o2) {
int dd1 = o1.getDateDay();
int mm1 = o1.getDateMonth();
//////years to compare ???????????????????
int years1 = o1.getYear();
int dd2 = o2.getDateDay();
int mm2 = o2.getDateMonth();
//////years to compare ?????????????????
int years2 = o2.getYear();
if (mm1 > mm2) {
return 1;
} else if (mm1 < mm2) {
return -1;
} else { // ==
if (dd1 > dd2) {
return 1;
} else if (dd1 < dd2) {
return -1;
} else {
return 0;
}
}
}
};
Collections.sort(list,dateCompare);
Compare the most significant field first. With a Date that is year.
Also, there is no need for a trailing else since the if and else if conditions return. Something like
if (years1 > years2) {
return 1;
} else if (years1 < years2) {
return -1;
}
if (mm1 > mm2) {
return 1;
} else if (mm1 < mm2) {
return -1;
}
if (dd1 > dd2) {
return 1;
} else if (dd1 < dd2) {
return -1;
}
return 0;
You could use the before() method of Date objects to compare the dates, it'll make writing code for your task very simple. Of course, that means that you have to convert your MyDate objects to Date but it should be very easy.
You can use the built-in functionality of the GregorianCalendar class to do this in a single line.
return new GregorianCalendar(years1, mm1 - 1, dd1).compareTo(new GregorianCalendar(years2, mm2 - 1, dd2));
Note that the - 1 in the month arguments are needed because the GregorianCalendar constructor uses a month value in the range of 0 to 11.
I am implementing a programm that creates and vehicle manager, with vehicle(objects) and those vehicle objects contain booking objects (with two Strings, one for the beginning date, and one for the end date) So I did some booking tests and it doesnt work. It must be in this method.
public boolean isBookable(Booking wishedBooking) {
boolean bookable = false;
if ((wishedBooking.begin.compareTo(begin) != 1
&& wishedBooking.end.compareTo(begin) != 1)
|| (wishedBooking.begin.compareTo(end) != -1
&& wishedBooking.end.compareTo(end) != -1)) {
bookable = true;
}
return bookable;
}
What I tried to do is to use compareTo. The dates have the format: YYYY/MM/DD HH:MM
So the only way the attempt booking can be done is when the begining and end of it is bellow or above one of the booking. If in one case it is not like that, it means that it cant be booked since at one time period of the time interval, there is already a booking. I am using != because it is possible that it can be equal, so the result will be 0.
The vehicle object now iterated with an methode over all the booking objects to check whether the booking can be done, os it is bookable.
Where is the mistake?
The contract of a.compareTo(b) is to return a value greater than 0 if a is "larger" than b, a value smaller than 0 if it's "smaller" or 0 if they are equal. Using 1 and -1 is purely an implementation detail, and you should not rely on it. I.e., your should change your code to:
public boolean isBookable(Booking wishedBooking) {
boolean bookable = false;
if ((wishedBooking.begin.compareTo(begin) <= 0
&& wishedBooking.end.compareTo(begin) <= 0)
|| (wishedBooking.begin.compareTo(end) >= 0
&& wishedBooking.end.compareTo(end) >= 0)) {
bookable = true;
}
return bookable;
}
Note that since you're only returning a boolean, the if can be removed, and you can just return its condition:
public boolean isBookable(Booking wishedBooking) {
return ((wishedBooking.begin.compareTo(begin) <= 0
&& wishedBooking.end.compareTo(begin) <= 0)
|| (wishedBooking.begin.compareTo(end) >= 0
&& wishedBooking.end.compareTo(end) >= 0));
}