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

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

}

运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring篇----第九篇

系列文章目录 文章目录 系列文章目录前言一、@Qualifier 注解有什么用?二、@RequestMapping 注解有什么用?三、spring DAO 有什么用?四、列举 Spring DAO 抛出的异常。前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到…

精益思维引领AI创新浪潮:从理念到实践的蜕变!

在人工智能&#xff08;AI&#xff09;飞速发展的今天&#xff0c;精益思维作为一种追求卓越、持续改进的管理哲学&#xff0c;正逐渐成为推动AI创新的重要动力。本文&#xff0c;天行健咨询将探讨精益思维如何与AI创新相结合&#xff0c;以及这种结合如何推动科技进步和社会发…

JetBrains系列工具,配置PlantUML绘图

PlantUML是一个很强大的绘图工具&#xff0c;各种图都可以绘制&#xff0c;具体的可以去官网看看&#xff0c;或者百度。 PlantUML简述 https://plantuml.com/zh/ PlantUML语言参考指引 https://plantuml.com/zh/guide PlantUML语言是依赖Graphviz进行解析的。Graphviz是开源…

每日一题 2867统计树中的合法路径

2867. 统计树中的合法路径数目 题目描述&#xff1a; 给你一棵 n 个节点的无向树&#xff0c;节点编号为 1 到 n 。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi] 表示节点 ui 和 vi 在树中有一条边。 请你返回树中的 合法路…

【Linux深入剖析】进程优先级 | 命令行参数 | 环境变量

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.进程优先级2.Linux…

hot100刷题记录-哈希

一、两数之和 题目&#xff1a;https://leetcode.cn/problems/two-sum/description/?envTypestudy-plan-v2&envIdtop-100-liked 方法1&#xff1a;枚举 class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:for id, num in enumerate(nums)…

jmeter 按线程数阶梯式压测数据库

当前版本&#xff1a; jmeter 5.6.3mysql 5.7.39 简介 JMeter 通过 bzm - Concurrency Thread Group 来实现阶梯式压测&#xff0c;它并不是JMeter的官方插件&#xff0c;而是一种由Blazemeter提供的高级线程组插件。可以在不同的时间内并发执行不同数量的线程&#xff0c;模拟…

相册图片怎么压缩?3种方法教你压缩图片

相册图片怎么压缩&#xff1f;相册图片压缩在日常生活中扮演着至关重要的角色。它不仅能够帮助我们节省手机或电脑的存储空间&#xff0c;避免设备因存储空间不足而运行缓慢&#xff0c;还能显著减少图片在上传、下载或分享时的时间。此外&#xff0c;压缩图片还能在一定程度上…

[算法沉淀记录] 排序算法 —— 选择排序

排序算法 —— 选择排序 基本概念 选择排序是一种简单的排序算法&#xff0c;它的工作原理是每次从待排序的列表中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;将其与列表中的第一个位置交换&#xff0c;然后继续对剩余的元素进行排序&#xff0c;直到整个列表…

【Java程序员面试专栏 算法思维】四 高频面试算法题:回溯算法

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊回溯算法,主要就是排列组合问题,所以放到一篇Blog中集中练习 题目关键字解题思路时间空间岛屿数量网格搜索分别向上下左右四个方向探索,遇到海洋…

R绘图 | 单列数据的分布图,对A变量分bin求B变量的平均值

问题1&#xff1a;单个向量的 density 分布图&#xff1f; (1) 模拟数据 set.seed(202402) datdiamonds[sample(nrow(diamonds), 1000),]> head(dat) # A tibble: 6 10carat cut color clarity depth table price x y z<dbl> <ord> &l…

数据可视化引领智慧仓储新时代

随着科技的飞速发展&#xff0c;数据可视化已然成为智慧仓储领域的璀璨明珠&#xff0c;其强大的功能和多面的作用让智慧仓储焕发出勃勃生机。让我们一同探索&#xff0c;数据可视化究竟在智慧仓储中起到了怎样的作用。下面我就以可视化从业者的角度来简单谈谈这个话题。 在这…

Linux——进程概念

目录 冯诺依曼体系结构 操作系统 管理 系统调用和库函数 进程的概念 进程控制块——PCB 查看进程 通过系统调用获取进程标示符 通过系统调用创建进程 进程状态 运行状态-R ​编辑 浅度睡眠状态-S 深度睡眠状态-D 暂停状态-T 死亡状态-X 僵尸状态-Z 僵尸进程…

详解顺序结构滑动窗口处理算法

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

WPF 附加属性+控件模板,完成自定义控件。建议观看HandyControl源码

文章目录 相关连接前言需要实现的效果附加属性添加附加属性&#xff0c;以Test修改FontSize为例依赖属性使用触发器使用直接操控 结论 控件模板&#xff0c;在HandyControl的基础上面进行修改参考HandyControl的源码控件模板原型控件模板 控件模板触发器完整样式简单使用 结论 …

光学3D表面轮廓仪微纳米三维形貌一键测量

光学3D表面轮廓仪(白光干涉仪)利用白光干涉原理&#xff0c;以0.1nm分辨率精准捕捉物体的表面细节&#xff0c;实现三维显微成像测量&#xff0c;被广泛应用于材料学领域的研究和应用。 了解工作原理与技术 材料学领域中的光学3D表面轮廓仪&#xff0c;也被称为白光干涉仪&am…

低价对品牌渠道的危害

品牌价值的体现主要在价格&#xff0c;比如要与竞品体现差异&#xff0c;除了产品功能上有做出差异&#xff0c;价格上也需要设置不同的阶梯&#xff0c;但如果经销商不遵守这个体系&#xff0c;或者非授权店铺随意低价&#xff0c;对于品牌来说都是非常不好的事情&#xff0c;…

Django后台管理(二)

一、自定义注册管理类介绍 官网:Django 管理站点 | Django 文档 | Django 注册模型除了使用 Django 默认的管理类admin,也可以自定义,比如: class StudentAdmin(admin.ModelAdmin):pass admin.site.register(Student, StudentAdmin)ModelAdmin 类是管理界面中模型的表示。…

微信小程序 wxs内联与外联的写法

内联写法 <!-- 内联wxs --> <view>大写字母{{m1.toUpper("xmly")}}</view> <wxs module"m1">module.exports.toUpperfunction(str){return str.toUpperCase()} </wxs> 外联写法 新建一个wxs文件 写一个函数&#xff0c;将…