Java8stream中利⽤groupingBy进⾏多字段分组求和Java8的groupingBy实现集合的分组,类似Mysql的group by分组功能,注意得到的是⼀个map
对集合按照单个属性分组、分组计数、排序
List<String> items =
Arrays.asList("apple", "apple", "banana",
"apple", "orange", "banana", "papaya");
// 分组
Map<String, List<String>> result1 = items.stream().collect(
Function.identity()
)
);
//{papaya=[papaya], orange=[orange], banana=[banana, banana], apple=[apple, apple, apple]}
System.out.println(result1);
// 分组计数
Map<String, Long> result2 = items.stream().collect(
Function.identity(), unting()
)
);
// {papaya=1, orange=1, banana=2, apple=3}
System.out.println(result2);
Map<String, Long> finalMap = new LinkedHashMap<>();
/
/分组, 计数和排序
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEachOrdered(e -> finalMap.Key(), e.getValue()));
// {apple=3, banana=2, papaya=1, orange=1}
System.out.println(finalMap);
集合按照多个属性分组
1.多个属性拼接出⼀个组合属性
public static void main(String[] args) {
User user1 = new User("zhangsan", "beijing", 10);
User user2 = new User("zhangsan", "beijing", 20);
User user3 = new User("lisi", "shanghai", 30);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
Map<String, List<User>> collect = list.stream().upingBy(e -> fetchGroupKey(e)));
//{zhangsan#beijing=[User{age=10, name='zhangsan', address='beijing'}, User{age=20, name='zhangsan', address='beijing'}],    // lisi#shanghai=[User{age=30, name='lisi', address='shanghai'}]}
System.out.println(collect);
}
private static String fetchGroupKey(User user){
Name() +"#"+ Address();
}
2.嵌套调⽤groupBy
User user1 = new User("zhangsan", "beijing", 10);
User user2 = new User("zhangsan", "beijing", 20);
User user3 = new User("lisi", "shanghai", 30);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
Map<String, Map<String, List<User>>> collect
= list.stream().collect(
User::getAddress, upingBy(User::getName)
)
);
System.out.println(collect);
3. 使⽤Arrays.asList
我有⼀个与Web访问记录相关的域对象列表。这些域对象可以扩展到数千个。
我没有资源或需求将它们以原始格式存储在数据库中,因此我希望预先计算聚合并将聚合的数据放在数据库中。
我需要聚合在5分钟窗⼝中传输的总字节数,如下⾯的sql查询
select
round(request_timestamp, '5') as window, --round timestamp to the nearest 5 minute
cdn,
isp,
http_result_code,
transaction_time,
sum(bytes_transferred)
from web_recordsgroupby分组
group by
round(request_timestamp, '5'),
cdn,
isp,
http_result_code,
transaction_time
在java 8中,我当前的第⼀次尝试是这样的,我知道这个解决⽅案类似于
Map<Date, Map<String, Map<String, Map<String, Map<String, Integer>>>>>>> aggregatedData =
webRecords
.stream()
.upingBy(WebRecord::getFiveMinuteWindow,
WebRecord::getReqBytes(),
Integer::sum)))))));
这是可⾏的,但它是丑陋的,所有这些嵌套的地图是⼀个噩梦!要将地图“展平”或“展开”成⾏,我必须这样做
for (Date window : aggregatedData.keySet()) {
for (String cdn : (window).keySet()) {
for (String isp : (window).get(cdn).keySet()) {
for (String resultCode : (window).get(cdn).get(isp).keySet()) {
for (String txnTime : (window).get(cdn).get(isp).get(resultCode).keySet()) {
Integer bytesTransferred = (window).get(cdn).get(distId).get(isp).get(resultCode).get(txnTime);
AggregatedRow row = new AggregatedRow(window, cdn,
如你所见,这是相当混乱和难以维持。
有谁知道更好的⽅法吗?任何帮助都将不胜感激。
我想知道是否有更好的⽅法来展开嵌套的映射,或者是否有⼀个库允许您对集合进⾏分组。
最佳答案
您应该为地图创建⾃定义密钥。最简单的⽅法是使⽤Arrays.asList:
Function<WebRecord, List<Object>> keyExtractor = wr ->
Arrays.<Object>FiveMinuteWindow(), wr.getCdn(), wr.getIsp(),
Map<List<Object>, Integer> aggregatedData = webRecords.stream().collect(
在这种情况下,键是按固定顺序列出的5个元素。不是很⾯向对象,但很简单。或者,您可以定义⾃⼰的表⽰⾃定义键的类型,并创建适当的hashCode/equals实现。
参考链接:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。