由于公司的api做了升级,所以最近要迁移自己写的druid查询部分的代码到新项目,然后在迁移的时候有一段用到lambda表达式来求和的例子,时间有些长了一开始看还有些懵,又重新温习了一下,下面写一下整体思路吧(以下是自己编的例子,和业务思想一样):

需求:需要通过druid api根据matchType作为透视维度,查看每个matchType的点击量和薪水,构造的对象如下:

@Data // lombok注解
@Builder // lombok注解
static class Person {private double salary;private int click;private String matchType;
}

执行的伪sql为:SELECT SUM(salary) AS salary, SUM(click) AS click, matchType FROM DRUID_XXXX GROUP BY matchType

通过druid api查询得到处理之后的结果如下:

{"result": [{"salary": 100.1,"click": 101,"matchType": "pc"},{"salary": 100.2,"click": 102,"matchType": "mb"},{"salary": 100.3,"click": 103,"matchType": "ny"}]
}

把以上的结果构造成JsonObject如下:

List<JsonObject> result = Arrays.asList( new Gson().toJsonTree(Person.builder().salary(100.1).click(101).matchType("pc").build()).getAsJsonObject(),new Gson().toJsonTree(Person.builder().salary(100.2).click(102).matchType("mb").build()).getAsJsonObject(),new Gson().toJsonTree(Person.builder().salary(100.3).click(103).matchType("ny").build()).getAsJsonObject()
);

由于druid的查询api对sum的指标有要求,这里提一下为下面写函数做准备:double类型的字段求和计算公式是doubleSum;int或者long类型的字段的求和计算公式是longSum(区别mysql,mysql求和无论double或者long/int都是sum),我们再写一个JavaBean保存一下上面指标的计算公式(其实就是指标的类型信息,long或者double),javaBean如下:

@Data // lombok注解
@Builder // lombok注解
static class Agg {private String name;private String type;
}
List<Agg> aggregations = Arrays.asList( // 这样查询结果所有指标的类型就存到aggregations这里面了Agg.builder().name("salary").type("doubleSum").build(),Agg.builder().name("click").type("longSum").build()
);

下面是最重要的部分:通过reduce求每个指标的合计

JsonObject jsonObject = result.stream().reduce(result.get(0),(iterate, item) -> {// 我们需要把第一个JsonObject的维度信息去掉, 最后的合计不需要维度if (iterate == item) {requestJson.getDimensions().forEach(item::remove);return item;}aggregations.forEach(aggregation -> {String name = aggregation.getName();if ("doubleSum".equalsIgnoreCase(aggregation.getType())) {iterate.addProperty(name, iterate.get(name).getAsDouble() + item.get(name).getAsDouble());} else {iterate.addProperty(name, iterate.get(name).getAsLong() + item.get(name).getAsLong());}});return iterate;}
);

这里解释一下,我们可以先看一下reduce函数的源码:

T reduce(T identity, BinaryOperator<T> accumulator);

T identity:identity的英语翻译是恒等式,也就是计算(函数)的初始值

BinaryOperator<T> accumulator:accumulator的英语翻译是累加器,也就是我们的函数。

可以看一下源码方法官方给的解释:

This is equivalent
* to:
* <pre>{@code
*     T result = identity;
*     for (T element : this stream)
*         result = accumulator.apply(result, element)
*     return result;
* }</pre>
*

这个解释应该很通俗易懂了:reduce方法的第一个参数作为初始值赋给apply方法的第一个参数,然后遍历当前流通过apply(我们自己的业务逻辑)实现求合计或者其他的目的,本章中是求合计

然后再回头看上面自己实现的代码:

我们把reduce方法中的第一个参数设置为result集合的第一个元素,该元素的类型是JsonObject

第二个参数,(iterate, item) 参数列表中的 iterate 第一次代表 reduce的第一个参数,也就是result.get(0),以后每次都代表求和之后的JsonObject。item代表result集合的流,第一次也是从result.get(0)开始,所以第一次开始执行时如果不处理的话会多算一次result.get(0)的JsonObject中的指标,顺便我们可以把result.get(0)的JsonObject中的的维度去掉,最终结果中我们只需要指标的合计,并不需要维度。

(iterate, item) -> {...} 大括号中的实现逻辑看上面“最重要的部分”的代码,这是我们的求和函数: 遍历指标名称,通过指标类型求和后返回累加后的结果,最终返回的结果打印如下:

{"salary":300.6,"click":306}

小小注意事项:

1. reduce函数在第一次执行时如果我们没有处理维度信息,返回的结果打印如下:

{"salary":300.6,"click":306,"matchType":"pc"}

会加上result集合第一个元素中的维度信息。

2. reduce函数在第一次执行时,由于初始值和当前流的第一个元素相同,如果不处理(把if (iterate == item)的逻辑去掉),返回的结果打印如下:

{"salary":400.7,"click":407,"matchType":"pc"}

可以看到多算了result集合第一个元素中的指标一次

** 附上整体的代码:

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.Builder;
import lombok.Data;import java.util.Arrays;
import java.util.Collections;
import java.util.List;public class ReduceTest {public static void main(String[] args) {List<JsonObject> result = Arrays.asList(new Gson().toJsonTree(Person.builder().salary(100.1).click(101).matchType("pc").build()).getAsJsonObject(),new Gson().toJsonTree(Person.builder().salary(100.2).click(102).matchType("mb").build()).getAsJsonObject(),new Gson().toJsonTree(Person.builder().salary(100.3).click(103).matchType("ny").build()).getAsJsonObject());Dimensions dimensions = Dimensions.builder().dimensions(Collections.singletonList("matchType")).build();List<Agg> aggregations = Arrays.asList(Agg.builder().name("salary").type("doubleSum").build(),Agg.builder().name("click").type("longSum").build());JsonObject jsonObject = result.stream().reduce(result.get(0),(iterate, item) -> {// 我们需要把第一个JsonObject的维度信息去掉, 最后的合计不需要维度if (iterate == item) {dimensions.getDimensions().forEach(item::remove);return item;}aggregations.forEach(aggregation -> {String name = aggregation.getName();if ("doubleSum".equalsIgnoreCase(aggregation.getType())) {iterate.addProperty(name, iterate.get(name).getAsDouble() + item.get(name).getAsDouble());} else {iterate.addProperty(name, iterate.get(name).getAsLong() + item.get(name).getAsLong());}});return iterate;});System.out.println(jsonObject);}@Data@Builderstatic class Person {private double salary;private int click;private String matchType;}@Data@Builderstatic class Dimensions {private List<String> dimensions;}@Data@Builderstatic class Agg {private String name;private String type;}
}

===========================割===========================

理解了以后再看没什么,但是要把想法转成文字真的好难。。

lambda之reduce函数相关推荐

  1. pythonpr函数_python reduce()函数

    reduce()函数 reduce()函数也是Python内置的一个高阶函数.reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传 ...

  2. python中集合所用的reduce_Python中reduce函数和lambda表达式的学习

    reduce函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1.2 个元素进行操作,得到的结果再与第三个数据用 ...

  3. python中的zip、map、reduce 、lambda、filter函数的使用

    飞机票 lambda函数 lambda只是一个表达式,函数体比def简单很多. lambda的主体是一个表达式,而不是一个代码块.仅仅能在lambda表达式中封装有限的逻辑进去. lambda表达式是 ...

  4. Python中lambda、zip、map、reduce函数的使用

    一.lambda表达式 lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数.lambda所表示的匿名函数的内容应该是很简单的,如果复杂的话,干脆就重新 ...

  5. Python3不存在reduce函数

    原文: https://blog.csdn.net/nigelyq/article/details/79283014 原因 翻阅原文:http://www.artima.com/forums/flat ...

  6. Python join sorted sort map reduce 函数解析

    为什么80%的码农都做不了架构师?>>>    1.字符串转list (list) s = 'abcde'     print list(s) ['a', 'b', 'c', 'd' ...

  7. python reduce()函数

    欢迎关注本人博客:云端筑梦师 描述 reduce() 函数会对参数序列中元素进行累积.函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 function(有两个参 ...

  8. Python编程基础:第五十七节 reduce函数Reduce

    第五十七节 reduce函数Reduce 前言 实践 前言 reduce函数的作用是逐项将迭代器的前两项按照指定方式进行计算,例如我们有一个数字列表[1, 2, 3, 4]我们可以使用reduce函数 ...

  9. python中的reduce() 函数

    在 Python3 中,reduce() 函数已经被从全局命名空间里移除了,它现在被放置在 functools 模块里,需要通过引入 functools 模块来调用 reduce() 函数: from ...

最新文章

  1. python turtle画画 30排以内_Python竟能画这么漂亮的花,帅呆了(代码分享)
  2. 为 Neutron 准备物理基础设施(II) - 每天5分钟玩转 OpenStack(76)
  3. OpenCV gPhoto2 VideoCapture的用法(附完整代码)
  4. python matlib库_python matplotlib 库学习
  5. mysql中的联结_MySQL的联结(Join)语法
  6. 苹果手机投屏win10电脑
  7. 表格里加横线一分为二_表格分割线如何一分为二
  8. CCS之最少拍控制器设计
  9. visio 怎么画直线
  10. XMLHttpRequest请求跨域问题解决方案
  11. CTex winEdit报错“系统找不到指定文件”怎么办
  12. Java多线程+IO流+网络编程+MySQL+JDBC编程实现多人联机版坦克大战
  13. 华为emul升级_EMUI11正式版下载_华为emui11下载最新完整包2020(附升级教程及支持型号)-刷机之家...
  14. 【字符串】字符串逆序
  15. 证明:无理数的无理数次方是否还是无理数
  16. Spring-Redis实现分布式环境下主子域名Session共享
  17. Python 获取 网易云音乐热门评论(python2/python3代码)
  18. Android OpenGL ES 渲染文本
  19. apue学习第九天——标准I/O库(第五章)
  20. mac下 内存分析工具mat安装,使用mat分析:内存溢出、内存泄漏,结合jstat、jmap等命令的使用

热门文章

  1. 如何做好FAE工作及FAE职位发展————资深FAE总结推荐
  2. FileNotFoundException(系统找不到指定的路径)
  3. python基础知识1---python相关介绍
  4. 游戏开发手记:战斗模块设计
  5. javascript插入before(),after()新DOM方法
  6. 2022年大连理工大学计算机考研复试时间与复试范围
  7. 记录一段难忘的秋招时光
  8. 穷小子云计算创业暴富成功报复前老板
  9. php cacti,cacti搭建遇到的那些事
  10. ASEMI电磁炉整流桥KBJ2510参数和性能