41.仿简道云公式函数实战-数学函数-SUMIF
1. SUMIF函数
SUMIF 函数可用于计算子表单中满足某一条件的数字相加并返回和。
2. 函数用法
SUMIF(range, criteria, [sum_range])
其中各参数的含义及使用方法如下:
-
range:必需;根据 criteria 的条件规则进行检测的判断字段。支持的字段包括:子表单中的数字、单行文本、下拉框、单选按钮组;
-
criteria:必需;用于判断的条件规则。支持的形式和使用规则如下表:
支持形式 | 是否需要加引号 | 示例 | 注意事项 |
数字 | 不需要 | 20、32 | |
表达式 | 需要 | “>32”、"!=苹果" | 支持的运算符号包括:>、<、==、!=、>=、<= |
文本 | 需要 | “苹果”、"水果" | |
字段 | 不需要 | 字段 | 1)在主表字段中使用 SUMIF 函数时,只能选择主表字段2)在子表字段中使用 SUMIF 函数时,只能选择择主表字段和当前子表字段 |
3. 函数示例
如,计算入库明细中产品类型为「水果」的全部入库数量,则可以在「水果类数量总计」字段设置公式为:
4. 代码实战
首先我们在function包下创建math包,在math包下创建SumIfFunction类,代码如下:
package com.ql.util.express.self.combat.function.math;import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ql.util.express.Operator;
import com.ql.util.express.self.combat.exception.FormulaException;import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;/*** 类描述: SUMIF函数** @author admin* @version 1.0.0* @date 2023/11/24 10:33*/
public class SumIfFunction extends Operator {public SumIfFunction(String name) {this.name = name;}@Overridepublic Object executeInner(Object[] lists) throws Exception {//边界判断if (lists.length == 0 || lists.length<3 || lists.length >4) {throw new FormulaException("操作数异常");}BigDecimal res = BigDecimal.ZERO;Object range = null;Object criteria = null;List<Map<String,Object>> subFormVal =null;String rangeS ="";String key = "";if (lists.length == 3) { // 两个参数// 获取参数key = lists[0].toString();range = lists[1];criteria = lists[2];rangeS = range.toString();subFormVal = JSON.parseObject(key,List.class);res = cal(subFormVal,rangeS,criteria.toString(),rangeS);} else {// 三个参数处理Object sumRange = lists[3];key = lists[0].toString();range = lists[1];criteria = lists[2];rangeS = range.toString();subFormVal = JSON.parseObject(key,List.class);// 循环subFormVal集合res = cal(subFormVal,rangeS,criteria.toString(),sumRange.toString());}return res;}// 计算结果private BigDecimal cal(List<Map<String, Object>> list, String range, String criteria, String sumRange) {// criteria判断类型boolean isNum = CriteriaUtil.isNum(criteria);boolean isExpress = CriteriaUtil.isExpress(criteria);// 根据criteria类型 生成PredicateList<Map<String, Object>> collect =null;if (isExpress) {// 如果是表达式// 提取符号String symbol = CriteriaUtil.extractSymbol(criteria);String symbol_value = criteria.replaceAll(symbol,"");boolean sybolValueIsNum = CriteriaUtil.isNum(symbol_value);if (sybolValueIsNum) {// 如果是数字collect = list.stream().filter(paramMap -> {boolean res = false;if ("==".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) == Double.parseDouble(symbol_value)?true:false;} else if (">".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) > Double.parseDouble(symbol_value)?true:false;} else if (">=".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) >= Double.parseDouble(symbol_value)?true:false;} else if ("<".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) < Double.parseDouble(symbol_value)?true:false;} else if ("<=".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) <= Double.parseDouble(symbol_value)?true:false;} else if ("!=".equals(symbol)) {res = Double.parseDouble(paramMap.get(range).toString()) != Double.parseDouble(symbol_value)?true:false;}return res;}).collect(Collectors.toList());} else {collect = list.stream().filter(paramMap -> {boolean res = false;if ("==".equals(symbol)) {res = String.valueOf(paramMap.get(range)).equals(symbol_value);} else if ("!=".equals(symbol)) {res = !(String.valueOf(paramMap.get(range)).equals(symbol_value));} else {throw new RuntimeException("字符暂不支持的操作符号为:"+symbol);}return res;}).collect(Collectors.toList());}} else {// 没有表达式 直接默认为==if (isNum) {// 如果是数字collect = list.stream().filter(paramMap -> Double.parseDouble(paramMap.get(range).toString()) == Double.parseDouble(criteria)?true:false).collect(Collectors.toList());} else {collect = list.stream().filter(paramMap -> String.valueOf(paramMap.get(range)).equals(criteria)).collect(Collectors.toList());}}// 满足条件的集合统计出来后,按照sumRange字段统计求和BigDecimal sum = BigDecimal.ZERO;for (Map<String,Object> map:collect) {BigDecimal tmp = new BigDecimal(map.get(sumRange).toString());sum = sum.add(tmp);}return sum;}static class CriteriaUtil {public static boolean isNum (String criteria) {return StrUtil.isNumeric(criteria);}public static boolean isExpress(String criteria) {List<String> symbols = Arrays.asList(">",">=","<","<=","==","!=");boolean res = symbols.stream().anyMatch(s -> criteria.contains(s));return res;}/**** 提取表达式中的符号* @param criteria* @return*/public static String extractSymbol(String criteria) {List<String> symbols = Arrays.asList(">",">=","<","<=","==","!=");final Optional<String> first = symbols.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return criteria.contains(s);}}).findFirst();return first.get();}}}
把SumIfFunction类注册到公式函数入口类中,代码如下:
package com.ql.util.express.self.combat.ext;import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressResourceLoader;
import com.ql.util.express.parse.NodeTypeManager;
import com.ql.util.express.self.combat.function.logic.*;
import com.ql.util.express.self.combat.function.math.*;/*** 类描述: 仿简道云公式函数实战入口类** @author admin* @version 1.0.0* @date 2023/11/21 15:29*/
public class FormulaRunner extends ExpressRunner {public FormulaRunner() {super();}public FormulaRunner(boolean isPrecise, boolean isTrace) {super(isPrecise,isTrace);}public FormulaRunner(boolean isPrecise, boolean isStrace, NodeTypeManager nodeTypeManager) {super(isPrecise,isStrace,nodeTypeManager);}public FormulaRunner(boolean isPrecise, boolean isTrace, IExpressResourceLoader iExpressResourceLoader, NodeTypeManager nodeTypeManager) {super(isPrecise,isTrace,iExpressResourceLoader,nodeTypeManager);}@Overridepublic void addSystemFunctions() {// ExpressRunner 的内部系统函数super.addSystemFunctions();// 扩展公式函数this.customFunction();}/**** 自定义公式函数*/public void customFunction() {// 逻辑公式函数this.addLogicFunction();// 数学公式函数this.addMathFunction();}public void addLogicFunction() {// AND函数this.addFunction("AND",new AndFunction("AND"));// IF函数this.addFunction("IF",new IfFunction("IF"));// IFS函数this.addFunction("IFS",new IfsFunction("IFS"));// XOR函数this.addFunction("XOR",new XorFunction("XOR"));// TRUE函数this.addFunction("TRUE",new TrueFunction("TRUE"));// FALSE函数this.addFunction("FALSE",new FalseFunction("FALSE"));// NOT函数this.addFunction("NOT",new NotFunction("NOT"));// OR函数this.addFunction("OR",new OrFunction("OR"));}public void addMathFunction() {// ABS函数this.addFunction("ABS",new AbsFunction("ABS"));// AVERAGE函数this.addFunction("AVERAGE",new AvgFunction("AVERAGE"));// CEILING函数this.addFunction("CEILING",new CeilingFunction("CEILING"));// RADIANS函数this.addFunction("RADIANS",new RadiansFunction("RADIANS"));// COS函数this.addFunction("COS",new CosFunction("COS"));// COT函数this.addFunction("COT",new CotFunction("COT"));// COUNT函数this.addFunction("COUNT",new CountFunction("COUNT"));// COUNTIF函数this.addFunction("COUNTIF",new CountIfFunction("COUNTIF"));// FIXED函数this.addFunction("FIXED",new FixedFunction("FIXED"));// FLOOR函数this.addFunction("FLOOR",new FloorFunction("FLOOR"));// INT函数this.addFunction("INT",new IntFunction("INT"));// LARGE函数this.addFunction("LARGE",new LargeFunction("LARGE"));// LOG函数this.addFunction("LOG",new LogFunction("LOG"));// MAX函数this.addFunction("MAX",new MaxFunction("MAX"));// MIN函数this.addFunction("MIN",new MinFunction("MIN"));// MOD函数this.addFunction("MOD",new ModFunction("MOD"));// POWER函数this.addFunction("POWER",new PowerFunction("POWER"));// PRODUCT函数this.addFunction("PRODUCT",new ProductFunction("PRODUCT"));// RAND函数this.addFunction("RAND",new RandFunction("RAND"));// ROUND函数this.addFunction("ROUND",new RoundFunction("ROUND"));// SIN函数this.addFunction("SIN",new SinFunction("SIN"));// SMALL函数this.addFunction("SMALL",new SmallFunction("SMALL"));// SQRT函数this.addFunction("SQRT",new SqrtFunction("SQRT"));// SUM函数this.addFunction("SUM",new SumFunction("SUM"));// SUMIF函数this.addFunction("SUMIF",new SumIfFunction("SUMIF"));}
}
创建测试用例
package com.ql.util.express.self.combat;import com.alibaba.fastjson.JSON;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.self.combat.ext.FormulaRunner;
import org.junit.Test;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 类描述: 实战测试类** @author admin* @version 1.0.0* @date 2023/11/21 15:45*/
public class CombatTest {@Testpublic void SUMIF() throws Exception{FormulaRunner formulaRunner = new FormulaRunner(true,true);// 创建上下文DefaultContext<String, Object> context = new DefaultContext<>();List<Map<String,Object>> list = new ArrayList<>();Map<String,Object> map = new HashMap<>();map.put("record.type","红富士");map.put("record.name","苹果");map.put("record.num",20.0);Map<String,Object> map2 = new HashMap<>();map2.put("record.type","红富士");map2.put("record.name","苹果");map2.put("record.num",42.0);Map<String,Object> map3 = new HashMap<>();map3.put("record.type","红星");map3.put("record.name","苹果");map3.put("record.num",30.0);Map<String,Object> map4 = new HashMap<>();map4.put("record.type","美国");map4.put("record.name","苹果");map4.put("record.num",13000.0);Map<String,Object> map5 = new HashMap<>();map5.put("record.type","夏黑");map5.put("record.name","葡萄");map5.put("record.num",15);Map<String,Object> map6 = new HashMap<>();map6.put("record.type","阳光玫瑰");map6.put("record.name","葡萄");map6.put("record.num",30);Map<String,Object> map7 = new HashMap<>();map7.put("record.type","芝麻蕉");map7.put("record.name","香蕉");map7.put("record.num","20");list.add(map);list.add(map2);list.add(map3);list.add(map4);list.add(map5);list.add(map6);list.add(map7);String s = JSON.toJSONString(list);String express = "SUMIF(aa,bb,cc,dd)";context.put("aa",s);context.put("bb","record.type");context.put("cc","!=美国");context.put("dd","record.num");Object object = formulaRunner.execute(express, context, null, true, true);System.out.println(object);}}
运行结果
相关文章:

41.仿简道云公式函数实战-数学函数-SUMIF
1. SUMIF函数 SUMIF 函数可用于计算子表单中满足某一条件的数字相加并返回和。 2. 函数用法 SUMIF(range, criteria, [sum_range]) 其中各参数的含义及使用方法如下: range:必需;根据 criteria 的条件规则进行检测的判断字段。支持的字段…...
挑战30天学完Python:Day22 爬虫
🎉 本系列为Python基础学习,原稿来源于 30-Days-Of-Python 英文项目,大奇主要是对其本地化翻译、逐条验证和补充,想通过30天完成正儿八经的系统化实践。此系列适合零基础同学,或仅了解Python一点知识,但又没…...

AI:138-开发一种能够自动化生成艺术品描述的人工智能系统
🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…...

智慧城市建设的新里程碑:公共服务电子支付大屏
随着科技的飞速发展,我们的生活正在经历前所未有的变革。电子支付的出现,无疑是这场变革中的一大亮点,它不仅改变了我们日常的支付方式,更成为智慧城市建设的重要一环,为公众提供了更加便捷、高效的服务体验。 在以前&…...
Netty之Decoder详解与实战
在这篇博客文章中,我们将深入探讨Netty框架中的一个核心组件——Decoder,并通过示例解释其工作原理及如何在Netty应用程序中使用它来处理网络通信中的数据解码。 1. 什么是Decoder? 在Netty中,Decoder是一种特殊类型的ChannelHa…...

PCIe P2P DMA全景解读
温馨提醒:本文主要分为5个部分,总计4842字,需要时间较长,建议先收藏! P2P DMA简介 P2P DMA软硬件支持 CXL P2P DMA原理差异 P2P DMA应用场景 P2P DMA技术挑战 一、P2P DMA简介 P2P DMA(Peer-to-Peer…...
【Git】window下大小写不敏感问题处理
在Windows环境下,Git因为文件名的大小写敏感性而导致了一些问题。 首先,Windows文件系统是不区分大小写的,这意味着在Windows中创建的两个文件名只有大小写不同,但字母顺序和字符完全相同的文件会被视为相同的文件。然而…...
【JS】【Vue3】【React】获取滚轮位置的方法:JavaScript、Vue 3和React示例
目录 使用JavaScript原生方法在Vue 3中获取滚轮位置在React中获取滚轮位置 随着Web应用程序的发展,滚轮位置的获取变得越来越重要,可以用于实现页面的滚动效果、导航条的隐藏和显示等功能。本文将探讨在JavaScript、Vue 3和React中获取滚轮位置的不同方法…...

什么是线程和进程?
什么是线程和进程? 文章目录 什么是线程和进程?何为进程?何为线程? Java 线程和操作系统的线程有啥区别?请简要描述线程与进程的关系,区别及优缺点?图解进程和线程的关系程序计数器为什么是私有的?虚拟机栈和本地方法栈为什么是私有的?一句话简单了…...

MaxScale实现mysql8读写分离
MaxScale 实验环境 中间件192.168.150.24MaxScale 22.08.4主服务器192.168.150.21mysql 8.0.30从服务器192.168.150.22mysql 8.0.30从服务器192.168.150.23mysql 8.0.30 读写分离基于主从同步 1.先实现数据库主从同步 基于gtid的主从同步配置 主库配置 # tail -3 /etc/my.…...

【c语言】内存函数
欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 memcpy函数的使用和模拟实现 memcpy函数的使用 memcpy函数的模拟实现 memmove的使用和模拟实现 memmove的使用 memmove的模拟实现 memset函数的使用 memcmp函数…...
规则引擎项目
https://github.com/expr-lang/expr https://github.com/gorules/zen...

Docker Image(镜像)
“脚印会旧而梦还在走” Docker 镜像介绍 (1) 如何理解镜像? 🎯 docker image本质就是一个 read-only(只读)文件,这个文件包含了文件系统、源码、库文件、依赖文件、工具等一些运行 application 所必须的文件。 🎯 我们也可以…...

qgis启动提示Could not load qgis_app.dll
qgis启动提示Could not load qgis_app.dll 报错信息 我安装了QGIS3.16和3.22和3.28,都无法运行,启动程序报错问题如下图所示 解决方法 在开始菜单运行OSGeo4W 然后进去看看已经下载的qgis有没有更新,如果有更新的话,就直接点…...
数据分析---Python与sql
目录 Python的pandas,如何实现SQL中的leftjoinPython的pandas,如何实现SQL中的unionPython的pandas,如何实现类似SQL中的where进行限制Python的pandas,如和实现SQL中的group byPython的pandas,如何删除某一列Python的pandas,如何实现SQL中的leftjoin 在Python的pandas库中…...

【Oracle】玩转Oracle数据库(六):模式对象管理与安全管理
前言 嘿,数据库大冒险家们!准备好迎接数据库管理的新挑战了吗?今天我们要探索的是Oracle数据库中的模式对象管理与安全管理!🛡️💻 在这篇博文【Oracle】玩转Oracle数据库(六)&#…...

微服务篇之限流
一、为什么要限流 1. 并发的确大(突发流量)。 2. 防止用户恶意刷接口。 二、限流的实现方式 1. Tomcat限流 可以设置最大连接数,但是每一个微服务都有一个tomcat,实现起来非常麻烦。 2. Nginx限流 (1)控…...
react脚手架
1.react概述 1.1 什么是react React是一个用于构建用户界面的JS库。 用户界面:HTML页面(前端) React主要用来写HTML界面,或构建Web应用 如果从MVC的角度来看,React仅仅是视图层(V),也就是只负…...

【Vue3】插槽使用和animate使用
插槽使用 插槽slot匿名插槽具名插槽插槽作用域简写 动态插槽transition动画组件自定义过渡class类名如何使用animate动画库组件动画生命周期appear transition- group过渡列表 插槽slot 插槽就是子组件中提供给父组件使用的一个占位符父组件可以在这个占位符智能填充任何模板代…...

HarmonyOS—低代码开发Demo示例
接下来为大家展示一个低代码开发的JS工程的Demo示例,使用低代码开发如下华为手机介绍列表的HarmonyOS应用/服务示例。 1.删除模板页面中的控件后,选中组件栏中的List组件,将其拖至中央画布区域,松开鼠标,实现一个List组…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...