求教 Java8 stream 代码

2020-02-25 01:51:34 +08:00
 zealinux

下面是已经从数据库 Sample 表取出得数据

uid date 	hour	clicks	views
1  02-10	18		1		2
1  02-10	19		2		2
1  02-19	08		3		2
2  02-11	18		10		2
2  02-11	19		20		2

现在想要 [ group by ] ( uid, date ), 然后 clicks 求和,views 求和,hour 这一列不要了。

uid date 		clicks	views
1  02-10		3		4
1  02-19		3		2
2  02-11		30		4

另外,如果一个 object 还有其他的字段,groupby 的时候不一定是求和,可能是其他运算。

晚上搜了一大堆都是简单的一个字段的 groupBy,像下面一样,且都是返回某个属性值 Long,

Map<String, Long> countMap = samples.stream()
	.collect(
		Collectors.groupingBy(o -> o.getUid(),
			Collectors.summingLong(Sample::getViews)));

其实我想得到对象(比如 sample 对象),求教

3558 次点击
所在节点    Java
18 条回复
lhx2008
2020-02-25 07:28:50 +08:00
所以要输出什么,你的对象 POJO 怎么写的?
sumarker
2020-02-25 08:10:58 +08:00
没看懂你的问题是什么?
Malthael
2020-02-25 08:16:51 +08:00
groupingBy 第二个参数你得自定义合并规则。
zealinux
2020-02-25 09:25:09 +08:00
@sumarker

其实我就是想要的是,类似 MySQL 的 group by 两个字段功能,且有些字段是 sum() 操作。

```
Map<String, Sample> countMap = samples.stream()
.collect(
Collectors.groupingBy(
(这里 groupBy 两个字段,uid, 和 date )
(这里返回是 Sample 对象));
```
zealinux
2020-02-25 09:27:26 +08:00
@lhx2008

我要输出 group by (两个字段) 后的结果集合 List<Sample>,

其余部分字段是累加。

----
这个表如果在 MySQL 里,SQL 会比较简单。
lhx2008
2020-02-25 09:38:49 +08:00
请问你 MAP<string,sample>怎么做到你的意思,先把返回值的类型确定一下
zhady009
2020-02-25 10:54:23 +08:00
用 toMap 就行了然后第 3 个参数 BinaryOperator 里面 key 一样时你把 clicks 和 views 相加
qinxi
2020-02-25 11:30:09 +08:00
samples.stream()
.collect(
Collectors.groupingBy(T::getId)其实返回值就是 Map<String,List<T>> 你要的 sample 不就在 Map 的 List 里面吗...
hrong
2020-02-25 13:44:32 +08:00
楼主就是来要代码的。。。

<pre>
public static void main(String[] args) {
Sample s1 = new Sample();
s1.setUuid(1);
s1.setDate("2-10");
s1.setHour(18);
s1.setClicks(1);
s1.setViews(2);

Sample s2 = new Sample();
s2.setUuid(1);
s2.setDate("2-10");
s2.setHour(19);
s2.setClicks(2);
s2.setViews(2);

Sample s3 = new Sample();
s3.setUuid(1);
s3.setDate("2-19");
s3.setHour(8);
s3.setClicks(3);
s3.setViews(2);

Sample s4 = new Sample();
s4.setUuid(2);
s4.setDate("2-11");
s4.setHour(18);
s4.setClicks(10);
s4.setViews(2);

Sample s5 = new Sample();
s5.setUuid(2);
s5.setDate("2-11");
s5.setHour(19);
s5.setClicks(20);
s5.setViews(2);

Collection<Sample> list = List.of(s1,s2,s3,s4,s5)
.stream()
.collect(collectingAndThen(toMap((Sample s) -> s.getUuid() + "_" + s.getDate(),
Function.identity(),
(Sample s, Sample a) -> {
int sumClick = s.getClicks() + a.getClicks();
int sumView = s.getViews() + a.getViews();
Sample result = new Sample();
result.setUuid(s.getUuid());
result.setDate(s.getDate());
result.setClicks(sumClick);
result.setViews(sumView);
return result;
}), s -> s.values()));
list.forEach(System.out::println);
}
</pre>
jimotudou
2020-02-25 14:10:23 +08:00
9 楼的可以满足楼主需求,但是你为何不直接在数据库写好 sql,在映射到实体类呢。
chanchan
2020-02-25 14:22:18 +08:00
Map<Integer, Map<String, Map<String,Integer>>> collect2 = list.stream().
collect(Collectors.groupingBy(Sample::getUid,
Collectors.toMap(Sample::getDate,v -> {
HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("clicks", v.getClicks()==null?0:v.getClicks());
map.put("views", v.getViews()==null?0:v.getViews());
return map;
},(a,b) -> {
a.put("clicks", a.get("clicks")+a.get("clicks"));
b.put("views", a.get("views")+a.get("views"));
return a;
})));

想了好一会儿...
Rwing
2020-02-25 14:40:44 +08:00
c#欢迎你
https://dotnetfiddle.net/zUSwU7


```
var data = new List<Sample>
{
new Sample {id = 1, date = "02-10", clicks = 1, views = 2},
new Sample {id = 1, date = "02-10", clicks = 2, views = 2},
new Sample {id = 1, date = "02-19", clicks = 3, views = 2},
new Sample {id = 2, date = "02-11", clicks = 4, views = 2},
new Sample {id = 2, date = "02-11", clicks = 5, views = 2},
};

var result = data.GroupBy(i => new { i.id, i.date })
.Select(g => new Sample
{
id = g.Key.id,
date = g.Key.date,
clicks = g.Sum(i => i.clicks),
views = g.Sum(i => i.views),
});
```
hrong
2020-02-25 16:41:12 +08:00
@jimotudou 楼主就是来要代码的,我写个 hello world 就够了,还要服务到 DAO 层啊? 也不问问他充够钱了吗。。。
hrong
2020-02-25 16:43:14 +08:00
@Rwing C#简洁多了,果然走在前头。。。Java 不思进取好多年了。。。
coer
2020-02-26 10:54:34 +08:00
@hrong hhh 牛皮,这几个函数我还是第一见
hrong
2020-02-26 12:17:45 +08:00
@coer 楼主拿完代码就不见了。已 block
zealinux
2020-02-26 22:35:16 +08:00
@hrong 不要 block 我,这几天都是昏天黑地的晚上上班。(到家都半夜了)
zealinux
2020-02-26 22:59:36 +08:00
@hrong
刚刚才验证了你的代码。居然 OK👌。
(只是暂时还是看不懂。)
Thanks a lot.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/647259

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX