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_records
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实现。
补充知识:java8 新特性 Stream流分组排序过滤多条件去重(最⼩、最⼤、平均、求和)
什么是 Stream?
Stream 是⽤函数式编程⽅式在集合类上进⾏复杂操作的⼯具,其集成了Java 8中的众多新特性之⼀的聚合操作,开发者可以更容易地使⽤Lambda表达式,并且更⽅便地实现对集合的查、遍历、过滤以及常见计算等。话不多说,直接上代码。
List<User> list = new ArrayList<User>();
list = Arrays.asList(
new User("⼩强", 11, "男"),
new User("⼩玲", 15, "⼥"),
new User("⼩虎", 23, "男"),
new User("⼩⾬", 26, "⼥"),
new User("⼩飞", 19, "男"),
new User("⼩玲", 15, "⼥")
);
//分组
Map<String, List<User>> listMap = list.stream().upingBy(User::getSex));
for(String key:listMap.keySet()){
System.out.print(key+"组:");
<(key).forEach(user -> System.out.Name()));
System.out.println();
}
//排序
list.stream().sorted(Comparatorparing(user-> Age()))
.forEach(user -> System.out.Name()));
//过滤
list.stream().filter(user -> Sex().equals("男")).List())
.forEach(user -> System.out.Name()));
//多条件去重
list.stream().llectingAndThen(
Comparatorparing(user -> Age() + ";" + Name()))), ArrayList::new))
.
forEach(user -> System.out.Name()));
//最⼩值
Integer min = list.stream().mapToInt(User::getAge).min().getAsInt();
//最⼤值
Integer max = list.stream().mapToInt(User::getAge).max().getAsInt();
//平均值
Double average = list.stream().mapToInt(User::getAge).average().getAsDouble();
//和
Integer sum = list.stream().mapToInt(User::getAge).sum();
System.out.println("最⼩值:"+min+", 最⼤值"+max+", 平均值:"+average+", 和:"+sum);
//分组求和
Map<String, IntSummaryStatistics> collect = list.stream().upingBy(User::getSex, Collectors.summarizingInt(User::getAge))); IntSummaryStatistics statistics1 = ("男");
IntSummaryStatistics statistics2 = ("⼥");
System.out.Sum());
System.out.Average());
System.out.Max());
System.out.Min());
System.out.Count());
System.out.Sum());
System.out.Average());
System.out.Max());
groupby分组System.out.Min());
System.out.Count());
//提取list中两个属性值,转为map
Map<String, String> userMap = list.stream().Map(User::getName, User::getSex));
System.out.Json(userMap))
//取出所有名字
List<String> names = list.stream().map(User::getName).List());
System.out.Json(names))
以上这篇Java8 stream 中利⽤ groupingBy 进⾏多字段分组求和案例就是⼩编分享给⼤家的全部内容了,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论