I have an object like following:
public class Resource {
int level;
String identifier;
boolean isEducational;
public Resource(String level, String identifier, boolean isEducational) {
this.level = level;
this.identifier = identifier;
this.isEducational = isEducational;
}
// getter and setters
}
And a list of these Resources like:
List<Resource> resources = Arrays.asList(new Resource(4, "a", true ),
new Resource(4, "b", false),
new Resource(3, "c", true ),
new Resource(3, "d", false ),
new Resource(2, "e", true ),
new Resource(2, "f" , false));
I want to sort this list by their level
property but this sorting should be done separately for isEducational
resources and non-isEducational
resources.
So, after sorting, the resultant list should be in the following order:
[Resource e, Resource c, Resource a, Resource f, Resource d, Resource b]
// basically, isEducational sorted first, followed by non-educational resources
So I tried following:
List<Resource> resources1 = resources.stream()
.collect(partitioningBy(r -> r.isEducational()))
.values()
.stream()
.map(list -> {
return list
.stream()
.sorted(comparing(r -> r.getLevel()))
.collect(toList());
})
.flatMap(Collection::stream)
.collect(toList());
resources1.stream().forEach(System.out::println);
And it prints the output as:
Resource{level='2', identifier='f', isEducational='false'}
Resource{level='3', identifier='d', isEducational='false'}
Resource{level='4', identifier='b', isEducational='false'}
Resource{level='2', identifier='e', isEducational='true'}
Resource{level='3', identifier='c', isEducational='true'}
Resource{level='4', identifier='a', isEducational='true'}
Which is opposite of what I want i.e. its printing non-educational first, followed by educational resources
Is there a better way to achieve this ? I do not want to iterate the list again to rearrange it. Thanks.
CodePudding user response:
No need to using partitioningBy
at all. You just need two comparators to first to compare by isEducational
and then by level
, which you can chain by using Comparator.thenComparing
resources.stream()
.sorted(Comparator.comparing(Resource::isEducational).reversed().thenComparing(Resource::getLevel))
.forEach(System.out::println);
You can introduce variables for the comparators to make your code more readable or if you want to reuse them in a flexible manner:
Comparator<Resource> byIsEdu = Comparator.comparing(Resource::isEducational).reversed();
Comparator<Resource> byLevel = Comparator.comparing(Resource::getLevel);
resources.stream()
.sorted(byIsEdu.thenComparing(byLevel))
.forEach(System.out::println);