Home > OS >  Interview question - Partition and Sort LocalDate objects using Java 8 features
Interview question - Partition and Sort LocalDate objects using Java 8 features

Time:10-29

I received this test-task for job, but I was rejected based on my solution. Please, give me a hint what would be the best way to solve this task.

As I found out later, they want me to use Java 8 features.

/**
 * Marking will be based upon producing a readable, well engineered solution rather than factors
 * such as speed of processing or other performance-based optimizations, which are less
 * important.
 *
 *
 * The Date sorter interface, implement the single method
 * within this interface.
 */
public interface IDateSorter {
    /**
     * The implementation of this method should sort dates.
     * The output should be in the following order:
     * Dates with an 'r' in the month,
     * sorted ascending (first to last),
     * then dates without an 'r' in the month,
     * sorted descending (last to first).
     * For example, October dates would come before May dates,
     * because October has an 'r' in it.
     * thus: (2005-07-01, 2005-01-02, 2005-01-01, 2005-05-03)
     * would sort to
     * (2005-01-01, 2005-01-02, 2005-07-01, 2005-05-03)
     *
     * @param unsortedDates - an unsorted list of dates
     * @return the collection of dates now sorted as per the spec
     */
    Collection<LocalDate> sortDates(List<LocalDate> unsortedDates);
}

This was my solution.

@Override
public  Collection<LocalDate> sortDates(List<LocalDate> unsortedDates) {
    List<LocalDate> listWithR = new ArrayList<>();
    List<LocalDate> listWithOutR = new ArrayList<>();

    //Separate unsortedDates in to list depends on 'R' factor
    for (LocalDate date: unsortedDates) {
        if (date.getMonth().getValue() < 5 || date.getMonth().getValue() > 8) {
            listWithR.add(date);
        } else {
            listWithOutR.add(date);
        }
    }
    //Sort list with R
    Collections.sort(listWithR);

    //Sort list without R
    listWithOutR.sort(Comparator.reverseOrder());

    //Adding list without R to list with R
    listWithR.addAll(listWithOutR);

    return listWithR;

}

CodePudding user response:

The given list can be sorted as required, in one go, without splitting it into two parts (and using Java 8 functional programming features as required).

Create a Comparator with Java 8

The approach boils down to defining the appropriate Comparator.

For that, we can use Java 8 static methods of the Comparator interface like Comparator.comparing().

The first part, which groups the dates based on the Month name, can be described as follows:

Comparator.comparing(ld -> !ld.getMonth().name().contains("R"))

Reminder: the natural order of boolean values is false -> true, for that reason condition was negated.

And we would need to check the same condition in the second part of the Comparator (because these groups of dates should be sorted differently), hence it makes sense to define a Predicate:

public static final Predicate<LocalDate> HAS_NO_R = ld -> !ld.getMonth().name().contains("R");

And the first part would be simplified to:

Comparator.comparing(HAS_NO_R::test)

To impose the required Ascending and Descending ordering, we can use ChronoLocalDate.toEpochDay(), returning the number of days from epoch as long, in conjunction with Comparator.thenComparingLong().

To make the group of date with no "R" in the name to be sorted in Descending order, the epoch count was reversed by multiplying by (-1).

thenComparingLong(ld -> HAS_NO_R.test(ld) ? (-1) * ld.toEpochDay() : ld.toEpochDay())

Complete Implementation

Now let's bring all the pieces together.

Comparator Predicate:

public static final Predicate<LocalDate> HAS_NO_R = ld -> !ld.getMonth().name().contains("R");
    
public final Comparator<LocalDate> BY_MONTH_R_ASC_NO_R_DESC =
    Comparator.comparing(HAS_NO_R::test)
        .thenComparingLong(ld -> HAS_NO_R.test(ld) ?
            (-1) * ld.toEpochDay() : ld.toEpochDay()
        );

And here's the method itself. We can make use of the Stream API to generate the sorted list:

public static Collection<LocalDate> sortDates(List<LocalDate> unsortedDates) {
    
    return unsortedDates.stream()         // assumption that original list should not be mutated
        .sorted(BY_MONTH_R_ASC_NO_R_DESC)
        .toList();
}

Note: I see no clear requirement on whether that method should return a new Collection. I've made a safe assumption that the original list should not be mutated.

Just for the purpose of completeness, that's the original list can be sorted with Java 9 List.sort():

unsortedDates.sort(BY_MONTH_R_ASC_NO_R_DESC);

return unsortedDates;

main()

public static void main(String[] args) {
    List<LocalDate> dates = List.of(
        LocalDate.parse("2005-07-01"), LocalDate.parse("2005-01-02"),
        LocalDate.parse("2005-01-01"), LocalDate.parse("2005-05-03")
    );

    sortDates(dates).forEach(System.out::println);
}

Output:

2005-01-01
2005-01-02
2005-07-01
2005-05-03
  • Related