如何使用partitioningBy,然后使用Java Streams分别对结果列表进行排序

Adh*_*mik 2 java sorting java-8 collectors

我有一个如下所示的对象:

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 
}
Run Code Online (Sandbox Code Playgroud)

这些资源的列表如下:

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));
Run Code Online (Sandbox Code Playgroud)

我想按其属性对这个列表进行排序,但是这种排序应该针对资源和资源level分别进行。isEducationalisEducational

因此,排序后,结果列表应按以下顺序排列:

[Resource e, Resource c, Resource a, Resource f, Resource d, Resource b]

// basically, isEducational sorted first, followed by non-educational resources
Run Code Online (Sandbox Code Playgroud)

所以我尝试了以下操作:

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);
Run Code Online (Sandbox Code Playgroud)

它将输出打印为:

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'}
Run Code Online (Sandbox Code Playgroud)

这与我想要的相反,即首先打印非教育资源,然后是教育资源

有没有更好的方法来实现这一目标?我不想再次迭代列表来重新排列它。谢谢。

Eri*_*ean 6

partitioningBy根本不需要使用。您只需要两个比较器,首先比较 by isEducational,然后比较 by level,您可以使用它们进行链接Comparator.thenComparing

resources.stream()
         .sorted(Comparator.comparing(Resource::isEducational).reversed().thenComparing(Resource::getLevel))
         .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

您可以为比较器引入变量,以使代码更具可读性,或者如果您想以灵活的方式重用它们:

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);
Run Code Online (Sandbox Code Playgroud)