I understand how to build and use Comparator
for lists of objects based on multiple attributes of those objects. However, I'm not sure how to do that efficiently by giving the user the choice of which parameters to sort by. This is a GWT
UI.
For example, I have two drop-down menus with 11 parameters each, corresponding to the attributes of the objects. Each menu also as a button beside to specify ascending/descending order.
So, the user may choose of example, to sort by fileName, desc
and timestamp, asc
. How can I sort these objects, without a ridiculously long if
statement for the few hundred possible combinations?
I could do this if the sort was fixed:
files.sort(Comparator.comparing(FileInfo::getFileName).thenComparing(FileInfo::getTimestamp).reversed());
(I might have got asc/desc backwards there)
But I shouldn't have to type that out for every conceivable option. So how should I do that?
You can try creating an enum:
public enum FileInfoComparator {
FILE_NAME(Comparator.comparing(FileInfo::getFileName)),
TIMESTAMP(Comparator.comparing(FileInfo::getTimestamp)),
SIZE(Comparator.comparing(FileInfo::getSize)),
// ... add other criteria here
;
private final Comparator<FileInfo> comparator;
FileInfoComparator(Comparator<FileInfo> comparator) {
this.comparator = comparator;
}
static Comparator<FileInfo> by(String key, boolean ascending) {
Comparator<FileInfo> comparator = valueOf(key).comparator;
return ascending ? comparator : comparator.reversed();
}
static Comparator<FileInfo> by(Pair<String, Boolean> criterion) {
return by(criterion.getKey(), criterion.getValue());
}
static Optional<Comparator<FileInfo>> by(List<Pair<String, Boolean>> criteria) {
return criteria.stream()
.map(FileInfoComparator::by)
.filter(Objects::nonNull)
.reduce(Comparator::thenComparing);
}
}
Then use:
// Create the list of selected criteria based on user input:
// E.g. [FILE_NAME, false] will mean "sort by fileName descending"
List<Pair<String, Boolean>> selectedCriteria = ...
// Build your comparator and sort your list
FileInfoComparator.by(selectedCriteria).ifPresent(files::sort);
In case of empty user selection the files
will remain untouched.