I have an unsorted list of objects:
List<Object> unsortedList = {objB, objB, objC, objA, objD, objA, ...}
My goal is to get a sorted list based on multiple conditions that looks something like this:
List<Object> sortedList = {objA, objA, objB, objC, objD, ...}
I know I could use a couple of different methods, for example Comparator:
Collections.sort(unsortedList, Comparator.comparing(Object::isAttributeA)
.thenComparing(Object::isAttributeB))
.thenComparing(Object::isAttributeC))...
However, the methods "isAttribute*" take in arguments/parameters related to the object at hand.
The needed logic in (not so pretty) for loop form looks as such:
for(Object obj : unsortedList){
if(obj.isAttributeA(obj)){
sortedList.add(obj);
}
}
for(Object obj : unsortedList){
if(obj.isAttributeB(obj.getField())){
sortedList.add(obj);
}
}
for(Object obj : unsortedList){
if(obj.isAttributeC(obj.getAnotherField())){
sortedList.add(obj);
}
}
Is there a better or more "elegant" way to iterate through a list of objects and sort it based on multiple conditions with objects satisfying the next condition being placed after those that satisfied the previous condition?
EDIT: The goal is to divide the unsorted list using some conditions into subgroups to assign priority for another method. In other words, there is another method that will be using this sorted list of objects to perform an action on each of the objects that has to be done in a certain order to avoid further problems.
CodePudding user response:
It sounds like what you want is actually something like
private static <T> int firstSatisfying(List<Predicate<T>> predicates, T t) {
for (int i = 0; i < predicates.size(); i ) {
if (predicates.get(i).test(t)) {
return i;
}
}
return predicates.size();
}
static final List<Predicate<Foo>> predicates = Arrays.asList(
Foo::isAttributeA, Foo::isAttributeB, ...);
Collections.sort(
unsortedList,
Comparator.comparingInt(t -> firstSatisfying(predicates, t)));
...if you want to sort the elements by the first matching condition, in some order of the conditions. This isn't the most efficient possible implementation, but it sounds like you only have a few conditions which are cheap to check, in which case this will do just fine.
CodePudding user response:
You can write a comparator that is not a method reference.
List<YourObject> sortedList = unsortedList.stream()
.sorted(Comparator.comparing((YourObject obj) -> obj.isAttributeA(obj))
.thenComparing(obj -> obj.isAttributeB(obj.getField()))
.thenComparing(obj -> obj.isAttributeC(obj.getAnotherField())))
.toList();