41.仿简道云公式函数实战-数学函数-SUMIF

news2025/2/27 8:26:51

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;
    }

    @Override
    public 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类型 生成Predicate
        List<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>() {
                @Override
                public 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);
    }

    @Override
    public 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 {

    @Test
    public 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);
    }

}

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1473528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

prime_series_level-1靶场详解

环境搭建 官网https://www.vulnhub.com/entry/prime-1,358/ 直接导入靶机 解题思路 arp-scan -l 确认靶机ip为192.168.236.136 也可以使用nmap扫网段 nmap -sn 192.168.236.0/24 使用nmap扫描靶机开放的端口 nmap -sS -T5 --min-rate 10000 192.168.236.136 -sC -p- &#xf…

ABBYY FineReader16文档转换、PDF管理与文档比较功能介绍

ABBYY FineReader 16作为一款OCR和PDF一体化程序&#xff0c;其强大的功能使得文档处理变得简单高效。在众多功能中&#xff0c;文档转换、PDF管理和文档比较这三大功能尤为突出&#xff0c;成为了众多企业和个人用户的首选工具。 ABBYY Finereader 16-安装包下载如下&#xff…

好书推荐丨AI绘画全面精通:软件平台+脚本文案+设计制作+案例实战

文章目录 写在前面AI绘画推荐图书图书简介本书特色作者简介 推荐理由粉丝福利写在后面 写在前面 本期博主给大家带来了一本全新出版的AI绘画类书籍&#xff0c;《AI绘画全面精通&#xff1a;软件平台脚本文案设计制作案例实战》&#xff0c;对人工智能感兴趣的小伙伴快来看看吧…

什么时候要用到Reflect API?

参考文档 https://www.zhihu.com/question/460133198 https://cn.vuejs.org/guide/extras/reactivity-in-depth.html https://juejin.cn/post/7103764386220769311 Reflect API 一般搭配 Proxy API 一起使用。什么是 Proxy API 呢&#xff1f; 先回顾下 vue 的数据响应性是如何…

27-树-左叶子之和

这是树的第27篇算法&#xff0c;力扣链接。 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 2…

前后端项目宝塔linux部署(springboot,vue,python)

宝塔linux安装就省略了&#xff0c;网上一堆 1.部署后端 1.首先把自己项目里面打包好的的jar包上传到服务器随便一个地方&#xff0c;我这里就上传到www/wwwroot下面了&#xff0c;宝塔的文件页面可以很便携上传 2.然后到下面这个页面 选那个java环境管理装个jdk&#xff…

在github的README.md中插入视频;在github的README.md中添加gif演示动画

最近需要再github中上传项目的源代码&#xff0c;应导师的要求&#xff0c;需要再README中加入对实验视频的展示&#xff0c;但是github的README.md其实就是一个markdown文件&#xff0c;据我的理解这个文件里应该无法直接插入视频吧&#xff1f;&#xff08;如果后续有办法直接…

【postgresql】数据表id自增与python sqlachemy结合实例

需求&#xff1a; postgresql实现一个建表语句&#xff0c;表名&#xff1a;student,字段id,name,age&#xff0c; 要求&#xff1a;每次添加一个数据id会自动增加1 在PostgreSQL中&#xff0c;您可以使用SERIAL或BIGSERIAL数据类型来自动生成主键ID。以下是一个创建名为stude…

2024环境,资源与绿色能源国际会议(ICERGE2024)

2024环境&#xff0c;资源与绿色能源国际会议(ICERGE2024) 一、【会议简介】 2024环境、资源与绿色能源国际会议(ICERGE2024)将于2024年在三亚举行。该会议是一个围绕环境、资源与绿色能源研究领域的国际学术交流活动。 会议主题包括但不限于环境科学、环境工程、资源利用、绿…

C++之类和对象(2)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 2. 赋值运算符只能重载成类的成员函数不能重载成全局函数 3. 用户没有显式实现时&…

pycharm如何安装pygame库

pycharm如何安装pygame库 PyCharm是Python中广受欢迎的一种IDE&#xff0c;它可以为用户提供许多工具和便利的服务&#xff0c;从而大大提高开发效率。pygame库可以用python进行游戏开发提供很好的支持&#xff0c;那么在ptcharm中如何安装pygame库呢&#xff1f; 一、安装步…

Sora背后的技术原理解析(简单易懂版本)

本篇文章是OpenAI发布的最强AI视频生成工具Sora技术详解&#xff08;非官方&#xff09;&#xff0c;然而&#xff0c;Sora的野心远不止是视频生成&#xff0c;而是作为一个世界模型。之前的文章中已经介绍了很多关于文生图的相关技术&#xff0c;相信有了文生图的基础后再来学…

[c/c++] static 关键字

从修饰的对象来看&#xff0c;static 可以修饰局部变量&#xff0c;也可以修饰全局变量&#xff0c;可以修饰函数&#xff1b;可以修饰类中的成员变量以及成员函数。 从生命周期的角度来看&#xff0c;static 修饰的对象的生命周期&#xff0c;与进程的生命周期是一致的。 从…

大话设计模式——3.建造者模式(Builder Pattern)

1.定义&#xff1a; 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。UML图 2.示例&#xff1a; 汽车或者电脑的组装可以采用构造者模式进行设计&#xff0c;如汽车的引擎或者轮胎&#xff0c;电脑的处理器、内存、主板等都可以进行…

【Java设计模式】四、适配器模式

文章目录 1、适配器模式2、举例 1、适配器模式 适配器模式Adapter Pattern&#xff0c;是做为两个不兼容的接口之间的桥梁目的是将一个类的接口转换成客户希望的另外一个接口适配器模式可以使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 最后&#xff0c;适配器…

【51单片机】红外遥控红外遥控电机调速(江科大)

1.红外遥控简介 红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出 通信方式:单工,异步 红外LED波长:940nm 通信协议标准:NEC标准 2.硬件电路 红外发送部分 IN高电平时&#xff0c;LED不亮&#xff0c;IN低电平时&…

Langchain-Chatchat:离线运行的大模型知识库 | 开源日报 No.182

chatchat-space/Langchain-Chatchat Stars: 22k License: Apache-2.0 基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现的开源、可离线部署的检索增强生成 (RAG) 大模型知识库项目。该项目是一个可以实现完全本地化推理的知识库增强方案&#xff0c;重点解决数据安全保护…

【C语言】linux内核netdev_start_xmit函数

一、中文注释 static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, bool more) {// 获取网络设备操作集合const struct net_device_ops *ops dev->netdev_ops;int rc;// 调用实际发送数据包的函数&…

RCS-YOLO:检测头和网络结构的改进

目录 摘要 原理 总体结构图 RCS模块原理 代码实现 RCS-Based One-Shot Aggregation 代码实现 检测头改进 手动计算anchor代码 yaml文件 已详细修改的代码 程序启动命令 可论文指导 V ------------> jiabei-545 往期推荐 摘要 凭借速度和准确性之间的出色平…

学习笔记-李沐动手学深度学习(七)(19-21,卷积层、填充padding、步幅stride、多输入多输出通道)

总结 19-卷积层 【补充】看评论区建议的卷积动画视频 数学中的卷积 【链接】https://www.bilibili.com/video/BV1VV411478E/?fromsearch&seid1725700777641154181&vd_sourcee81e116c4ffe5e79d4bc44738263eda4 【可判断是否为卷积的典型标志】两个函数中自变量相加…