Java 8 Map & Stream - 按值 desc 和组排序
Java 8 Map & Stream - Sorting by value desc and group
我需要在 Java 8.
中分组后,按计数总和对响应数据进行降序排序
我的视图 table 查询结果如下:
计数(bigint)
类别(varchar)
我的枚举(整数)
10
一个
0
35
B
0
30
一个
1
25
C
1
我有一个用于自定义 JPA 查询结果的视图 table 的投影界面。
public interface MyView {
Long getCount();
String getCategory();
MyEnum getMyEnum();
}
这是我的 DTO 回复:
public class MyResponse {
private List<Long> count = new ArrayList<>();
private List<String> categories = new ArrayList<>();
private List<List<MyEnum>> myEnums = new ArrayList<>();
// ctors, getters and setters
}
我需要按类别对数据进行分组并对总计数求和,然后将每个类别的枚举类型收集到一个列表中。据此,类别 A 的计数应为 40 并且具有 0,1 枚举类型。
所以,客户端在get请求后需要得到如下结果:
{
"count": [
40,
35,
25
],
"categories": [
"A",
"B",
"C"
],
"myEnums": [
[
"ENUM_A",
"ENUM_B"
],
[
"ENUM_A",
],
[
"ENUM_B",
]
]
}
这是我服务中的相关功能:
public MyResponse foo() {
// This list have the list of MyView.
List<MyView> myList = myRepository.getCountView());
Map<String, List<MyView>> myMap = myList.stream().collect(Collectors.groupingBy(MyView::getCategory));
MyResponse response = new MyResponse();
myMap.forEach((key, value) -> {
response.getCategories().add(key);
response.getCount().add(value.stream().mapToLong(MyView::getCount).sum());
response.getMyEnums().add(value.stream().flatMap(v -> Stream.of(v.getMyEnum())).collect(Collectors.toList()));
}
);
return response;
}
好的,我已经完成了按类别分组并对计数求和,但无法对它们进行排序。结果是正确的,但我需要按总计数降序排列数据。
如有任何建议,我将不胜感激。谢谢!
您可以 map
映射中的每个条目到 CategorySummary
,然后减少到 MyResponse
:
List<MyView> myList = Arrays.asList(
new MyView(30, "B", MyEnum.ENUM_B),
new MyView(10, "A", MyEnum.ENUM_A),
new MyView(35, "B", MyEnum.ENUM_A),
new MyView(25, "C", MyEnum.ENUM_B)
);
Map<String, List<MyView>> myMap = myList.stream()
.collect(Collectors.groupingBy(MyView::getCategory, TreeMap::new, Collectors.toList()));
MyResponse myResponse = myMap.entrySet().stream()
.map(e -> new CategorySummary(
e.getValue().stream().mapToLong(MyView::getCount).sum(),
e.getKey(),
e.getValue().stream().flatMap(v -> Stream.of(v.getMyEnum())).collect(Collectors.toList())
))
.sorted(Comparator.comparing(CategorySummary::getCount).reversed())
.reduce(new MyResponse(),
(r, category) -> {
r.addCategory(category);
return r;
}, (myResponse1, myResponse2) -> { // the combiner won't be invoked because it's sequential stream.
myResponse1.getMyEnums().addAll(myResponse2.getMyEnums());
myResponse1.getCount().addAll(myResponse2.getCount());
myResponse1.getCategories().addAll(myResponse2.getCategories());
return myResponse1;
});
System.out.println(new ObjectMapper().writeValueAsString(myResponse));
输出:
{
"count": [65, 25, 10],
"categories": ["B", "C", "A"],
"myEnums": [
["ENUM_B", "ENUM_A"],
["ENUM_B"],
["ENUM_A"]
]
}
CategorySummary
:
@AllArgsConstructor
@Getter
public class CategorySummary {
private long count;
private String name;
private List<MyEnum> myEnums;
}
我还必须在 MyResponse
class 中添加一个额外的方法:
public void addCategory(CategorySummary categorySummary){
this.count.add(categorySummary.getCount());
this.categories.add(categorySummary.getName());
this.myEnums.add(categorySummary.getMyEnums());
}
我需要在 Java 8.
中分组后,按计数总和对响应数据进行降序排序我的视图 table 查询结果如下:
计数(bigint) | 类别(varchar) | 我的枚举(整数) |
---|---|---|
10 | 一个 | 0 |
35 | B | 0 |
30 | 一个 | 1 |
25 | C | 1 |
我有一个用于自定义 JPA 查询结果的视图 table 的投影界面。
public interface MyView {
Long getCount();
String getCategory();
MyEnum getMyEnum();
}
这是我的 DTO 回复:
public class MyResponse {
private List<Long> count = new ArrayList<>();
private List<String> categories = new ArrayList<>();
private List<List<MyEnum>> myEnums = new ArrayList<>();
// ctors, getters and setters
}
我需要按类别对数据进行分组并对总计数求和,然后将每个类别的枚举类型收集到一个列表中。据此,类别 A 的计数应为 40 并且具有 0,1 枚举类型。 所以,客户端在get请求后需要得到如下结果:
{
"count": [
40,
35,
25
],
"categories": [
"A",
"B",
"C"
],
"myEnums": [
[
"ENUM_A",
"ENUM_B"
],
[
"ENUM_A",
],
[
"ENUM_B",
]
]
}
这是我服务中的相关功能:
public MyResponse foo() {
// This list have the list of MyView.
List<MyView> myList = myRepository.getCountView());
Map<String, List<MyView>> myMap = myList.stream().collect(Collectors.groupingBy(MyView::getCategory));
MyResponse response = new MyResponse();
myMap.forEach((key, value) -> {
response.getCategories().add(key);
response.getCount().add(value.stream().mapToLong(MyView::getCount).sum());
response.getMyEnums().add(value.stream().flatMap(v -> Stream.of(v.getMyEnum())).collect(Collectors.toList()));
}
);
return response;
}
好的,我已经完成了按类别分组并对计数求和,但无法对它们进行排序。结果是正确的,但我需要按总计数降序排列数据。 如有任何建议,我将不胜感激。谢谢!
您可以 map
映射中的每个条目到 CategorySummary
,然后减少到 MyResponse
:
List<MyView> myList = Arrays.asList(
new MyView(30, "B", MyEnum.ENUM_B),
new MyView(10, "A", MyEnum.ENUM_A),
new MyView(35, "B", MyEnum.ENUM_A),
new MyView(25, "C", MyEnum.ENUM_B)
);
Map<String, List<MyView>> myMap = myList.stream()
.collect(Collectors.groupingBy(MyView::getCategory, TreeMap::new, Collectors.toList()));
MyResponse myResponse = myMap.entrySet().stream()
.map(e -> new CategorySummary(
e.getValue().stream().mapToLong(MyView::getCount).sum(),
e.getKey(),
e.getValue().stream().flatMap(v -> Stream.of(v.getMyEnum())).collect(Collectors.toList())
))
.sorted(Comparator.comparing(CategorySummary::getCount).reversed())
.reduce(new MyResponse(),
(r, category) -> {
r.addCategory(category);
return r;
}, (myResponse1, myResponse2) -> { // the combiner won't be invoked because it's sequential stream.
myResponse1.getMyEnums().addAll(myResponse2.getMyEnums());
myResponse1.getCount().addAll(myResponse2.getCount());
myResponse1.getCategories().addAll(myResponse2.getCategories());
return myResponse1;
});
System.out.println(new ObjectMapper().writeValueAsString(myResponse));
输出:
{
"count": [65, 25, 10],
"categories": ["B", "C", "A"],
"myEnums": [
["ENUM_B", "ENUM_A"],
["ENUM_B"],
["ENUM_A"]
]
}
CategorySummary
:
@AllArgsConstructor
@Getter
public class CategorySummary {
private long count;
private String name;
private List<MyEnum> myEnums;
}
我还必须在 MyResponse
class 中添加一个额外的方法:
public void addCategory(CategorySummary categorySummary){
this.count.add(categorySummary.getCount());
this.categories.add(categorySummary.getName());
this.myEnums.add(categorySummary.getMyEnums());
}