Hello to all java gurus from a novice java developer, help me write a sorting algorithm for an object that is nested in another object, but at the same time must take into account the field of the main object
main object:
public class Review {
String date;
Update update;
}
update object:
public class Update {
String date;
}
My wrong algorithm:
public class Test {
public static void main(String[] args) {
Review review = new Review();
Update update = new Update();
update.date = LocalDateTime.now().toString();
review.date = LocalDateTime.now().minusDays(20L).toString();
review.update = update;
Review review1 = new Review();
Update update1 = new Update();
update1.date = LocalDateTime.now().minusDays(5L).toString();
review1.date = LocalDateTime.now().minusDays(30L).toString();
review1.update = update1;
Review review10 = new Review();
Update update10 = new Update();
update10.date = LocalDateTime.now().minusDays(1L).toString();
review10.date = LocalDateTime.now().minusDays(100L).toString();
review10.update = update10;
Review review2 = new Review();
review2.date = LocalDateTime.now().minusDays(40L).toString();
Review review3 = new Review();
review3.date = LocalDateTime.now().minusDays(50L).toString();
Review review4 = new Review();
review4.date = LocalDateTime.now().minusDays(2L).toString();
List<Review> reviews = List.of(review, review1, review2, review3, review4, review10);
Comparator<Review> reviewComparator = Comparator.comparing(review5 -> review5.date);
System.out.println(reviews = reviews.stream().sorted(reviewComparator.reversed()).collect(Collectors.toList()));
for (int i = 0; i < reviews.size(); i ) {
Review review5 = reviews.get(i);
for (int z = 1; z < reviews.size(); z ) {
if (z >= i) {
Review review6 = reviews.get(z);
if (review6.update != null) {
LocalDateTime date1 = LocalDateTime.parse(review6.update.date);
LocalDateTime date2 = LocalDateTime.parse(review5.date);
int i1 = date1.compareTo(date2);
if (i1 > 0) {
reviews.remove(review6);
reviews.add(i, review6);
} else if (review5.update != null) {
LocalDateTime date3 = LocalDateTime.parse(review6.update.date);
LocalDateTime date4 = LocalDateTime.parse(review5.update.date);
int i2 = date3.compareTo(date4);
if (i2 > 0) {
reviews.remove(review6);
reviews.add(i, review6);
}
}
}
}
}
}
System.out.println(reviews);
}
}
and result:
[
Review{date='2022-10-11T13:17:01.754934500', update=Update{date='2023-01-18T13:17:01.754934500'}},
Review{date='2022-12-20T13:17:01.754934500', update=Update{date='2023-01-14T13:17:01.754934500'}},
Review{date='2022-12-30T13:17:01.754934500', update=Update{date='2023-01-19T13:17:01.753935600'}},
Review{date='2023-01-17T13:17:01.754934500', update=null},
Review{date='2022-12-10T13:17:01.754934500', update=null},
Review{date='2022-11-30T13:17:01.754934500', update=null}
]
I expect:
[
Review{date='2022-12-30T13:17:01.754934500', update=Update{date='2023-01-19T13:17:01.753935600'}},
Review{date='2022-10-11T13:17:01.754934500', update=Update{date='2023-01-18T13:17:01.754934500'}},
Review{date='2023-01-17T13:17:01.754934500', update=null},
Review{date='2022-12-20T13:17:01.754934500', update=Update{date='2023-01-14T13:17:01.754934500'}},
Review{date='2022-12-10T13:17:01.754934500', update=null},
Review{date='2022-11-30T13:17:01.754934500', update=null}
]
CodePudding user response:
So you want to sort by Review.update.date
if it exists and Review.date
if it doesn't?
You can add that mapping in the key extractor function you're passing to Comparator.comparing(...)
:
Comparator.comparing(r -> r.update != null ? r.update.date : r.date);
Using this with Collections.sort(reviews, reviewComparator.reversed());
should result in the following list (I added my own toString
to make it easier to read):
Review [date=2022-12-30T12:13:27.102934100, update=2023-01-19T12:13:27.096938200]
Review [date=2022-10-11T12:13:27.103934400, update=2023-01-18T12:13:27.103934400]
Review [date=2023-01-17T12:13:27.103934400, update=null]
Review [date=2022-12-20T12:13:27.102934100, update=2023-01-14T12:13:27.102934100]
Review [date=2022-12-10T12:13:27.103934400, update=null]
Review [date=2022-11-30T12:13:27.103934400, update=null]
Note: depending on your design it might make sense to add a method into Review
that returns the last review date. I won't change too much of your code (like using proper date types) but it could look like this:
public class Review {
String date; //creation date
Update update;
public String getLastReviewDate() {
return update != null ? update.date : date;
}
}
Then the comparator would look like this: Comparator.comparing(Review::getLastReviewDate)
. It's easier to read and understand that the sorting is based on the virtual property "last review date".