Java集合去重合并以及汇总操作

一.背景
实际开发中,遇到了一个场景,需要对两个数据源集合进行去重合并,并且对去重合并后的结果集进行数据标签加工汇总。

二.场景演示
现在有两个数据源集合,分别来自不同的端,且两个数据源集合中结构是相同的。

模拟数据源集合1:

        Map<String, Object> m0 = new HashMap<>();
        m0.put("birthday", "1990年12月27日");
        m0.put("graduate", "2014年06月06日");
        m0.put("name", "张三");
        m0.put("money", "100.66");

        Map<String, Object> m1 = new HashMap<>();
        m1.put("birthday", "1992年11月11日");
        m1.put("graduate", "2016年06月08日");
        m1.put("name", "李四");
        m1.put("money", "200.88");
        
        List<Map<String,Object>> sourceList1 = new ArrayList<>();
        sourceList1.add(m0);
        sourceList1.add(m1); 

模拟数据源集合2:

        Map<String, Object> m2 = new HashMap<>();
        m2.put("birthday", "1991年09月01日");
        m2.put("graduate", "2015年06月07日");
        m2.put("name", "王五");
        m2.put("money", "300.99");

        Map<String, Object> m3 = new HashMap<>();
        m3.put("birthday", "1992年11月11日");
        m3.put("graduate", "2015年06月07日");
        m3.put("name", "李四");
        m3.put("money", "300.99");

        List<Map<String, Object>> sourcelist2 = new ArrayList<>();
        sourcelist2.add(m2);
        sourcelist2.add(m3);

现在需要对两个集合进行去重合并成一个集合,且去重的判定标准是Map中的name+birthday如果都是一样的则视为重复的,且保留sourceList1的结果。

ListUtil.java

package com.hong.util;

import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wanghong
 * @date 2019/04/03 22:27
 * 泛型化集合排序工具
 **/
public class ListUtil<T> {
    /**
     * 去重并合并
     * 对2个List根据某几个字段进行去重并将结果集合并到一个List中
     * l0,l1本身是不重复的,这里注意重复的记录只保留l0中的,所以在实际传参时需要注意l0和l1的顺序
     *
     * @param l0 数据源集合1
     * @param l1 数据源集合2
     * @return
     * @paran keys
     */
    public static List<Map<String, Object>> removeDuplicateAndMerge(List<Map<String, Object>> l0, List<Map<String, Object>> l1, String[] keys) {
        l0.addAll(l1);
      
        return l0.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> {
                    StringBuilder sb = new StringBuilder();
                    for (String key : keys) {
                        Object val = o.get(key);
                        if (val instanceof String) {
                            val = ((String) val).replaceAll("(", "(").replaceAll(")", ")");
                        }
                        sb.append(val);
                        sb.append(";");
                    }
                    return sb.deleteCharAt(sb.lastIndexOf(";")).toString();
                }))), ArrayList::new));
    }
}
        String[] keys = {"name","birthday"};
        List<Map<String, Object>> list = ListUtil.removeDuplicateAndMerge(sourceList1, sourcelist2, keys);
        System.out.println(list);

打印结果:

[{birthday=19901227, money=100.66, graduate=20140606, name=张三}, {birthday=19921111, money=200.88, graduate=20160608, name=李四}, {birthday=19910901, money=300.99, graduate=20150607, name=王五}]

从打印结果中可以看到重复的记录值只保留了sourceList1中的。

三.问题延申
现在需要统计去重合并后结果集中的birthday最小/大值,graduate的最小值,money的总和,如何做?

package com.hong.util;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;

/**
 * @author wanghong
 * @date 2019/04/26 17:25
 * 汇总操作工具类
 **/
public class OperateUtil {

    /**
     * 这里的核心思想是:在每一次遍历集合元素的过程中,同时比较最小/大值,和的累计,而不是将最小/大值的求解分开遍历
     *
     * @param list        数据集合
     * @param t           汇总结果封装对象
     * @param summaryList 需要汇总最大/小值/总和的字段信息
     * @param <T>
     */
    public static <T> void summarizing(List<Map<String, Object>> list, T t, List<Summary> summaryList) {

        if (CollectionUtils.isEmpty(list) || t == null || CollectionUtils.isEmpty(summaryList)) {
            return;
        }

        Map<String, Summary> fieldMap = new HashMap<>();
        for (Summary sm : summaryList) {
            fieldMap.put(sm.getField(), sm);
        }

        /**
         *  取出所有参与汇总的的源数据集字段
         */
        Set<String> fields = fieldMap.keySet();

        /**
         *  汇总结果集Map
         * 保存 汇总字段 -> 最小/大值/总和的映射
         */
        Map<String, Object> summaryMap = new HashMap<>();

        for (Map<String, Object> m : list) {
            for (String field : fields) {
                Object current = m.get(field);
                if (StringUtils.isEmpty(current)) {
                    continue;
                }

                Summary summary = fieldMap.get(field);
                String maxField = summary.getMaxField();
                String minField = summary.getMinField();
                String sumField = summary.getSumField();
                Comparator comparator = summary.getComparator();
                BinaryOperator binaryOperator = summary.getBinaryOperator();

                Object maxValue = summaryMap.get(maxField);
                Object minValue = summaryMap.get(minField);
                Object sumValue = summaryMap.get(sumField);

                if (!StringUtils.isEmpty(maxField)) {
                    if (maxValue == null || comparator.compare(current, maxValue) > 0) {
                        summaryMap.put(maxField, current);
                    }
                }

                if (!StringUtils.isEmpty(minField)) {
                    if (minValue == null || comparator.compare(current, minValue) < 0) {
                        summaryMap.put(minField, current);
                    }
                }

                if (!StringUtils.isEmpty(sumField)) {
                    if (sumValue == null) {
                        summaryMap.put(sumField, current);
                    } else {
                        summaryMap.put(sumField, binaryOperator.apply(current, sumValue));
                    }
                }
            }
        }

        Class<?> clazz = t.getClass();
        for (Map.Entry<String, Object> entry : summaryMap.entrySet()) {
            String key = entry.getKey();
            try {
                Field field = clazz.getDeclaredField(key);
                field.setAccessible(true);
                field.set(t, entry.getValue());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 private static class SummaryInfo {
        private String minBirthday;
        private String maxBirthday;
        private String name;
        private String minGraduate;
        private String sumMoney;

        public String getMinBirthday() {
            return minBirthday;
        }

        public void setMinBirthday(String minBirthday) {
            this.minBirthday = minBirthday;
        }

        public String getMaxBirthday() {
            return maxBirthday;
        }

        public void setMaxBirthday(String maxBirthday) {
            this.maxBirthday = maxBirthday;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getMinGraduate() {
            return minGraduate;
        }

        public void setMinGraduate(String minGraduate) {
            this.minGraduate = minGraduate;
        }

        public String getSumMoney() {
            return sumMoney;
        }

        public void setSumMoney(String sumMoney) {
            this.sumMoney = sumMoney;
        }

        @Override
        public String toString() {
            return "SummaryInfo{" +
                    "minBirthday='" + minBirthday + '\'' +
                    ", maxBirthday='" + maxBirthday + '\'' +
                    ", name='" + name + '\'' +
                    ", minGraduate='" + minGraduate + '\'' +
                    ", sumMoney='" + sumMoney + '\'' +
                    '}';
        }
    }
 /**
     * 汇总操作
     */
    public static class Summary {
        /**
         * 源数据集中需要汇总的字段
         */
        private String field;

        /**
         * 汇总后对应的最小值接收字段
         */
        private String minField;

        /**
         * 汇总后对应的最大值接收字段
         */
        private String maxField;

        /**
         * 自定义比较器
         */
        private Comparator comparator;

        /**
         * 汇总对应的总和接收字段
         */
        private String sumField;

        /**
         * 求和操作
         */
        private BinaryOperator binaryOperator;

        public String getField() {
            return field;
        }

        public void setField(String field) {
            this.field = field;
        }

        public String getMinField() {
            return minField;
        }

        public void setMinField(String minField) {
            this.minField = minField;
        }

        public String getMaxField() {
            return maxField;
        }

        public void setMaxField(String maxField) {
            this.maxField = maxField;
        }

        public Comparator getComparator() {
            return comparator;
        }

        public void setComparator(Comparator comparator) {
            this.comparator = comparator;
        }

        public String getSumField() {
            return sumField;
        }

        public void setSumField(String sumField) {
            this.sumField = sumField;
        }

        public BinaryOperator getBinaryOperator() {
            return binaryOperator;
        }

        public void setBinaryOperator(BinaryOperator binaryOperator) {
            this.binaryOperator = binaryOperator;
        }
    }
        SummaryInfo summaryInfo = new SummaryInfo();
        summaryInfo.setName("wanghong");

        Summary sc0 = new Summary();
        sc0.setField("birthday");
        sc0.setMinField("minBirthday");
        sc0.setMaxField("maxBirthday");
        sc0.setComparator(Comparator.comparing(DateUtil::parseDate));

        Summary sc1 = new Summary();
        sc1.setField("graduate");
        sc1.setMinField("minGraduate");
        sc1.setComparator(Comparator.comparing(DateUtil::parseDate));

        Summary sc2 = new Summary();
        sc2.setField("money");
        sc2.setSumField("sumMoney");
        sc2.setBinaryOperator((a, b) -> {
            BigDecimal b0 = new BigDecimal(a.toString());
            BigDecimal b1 = new BigDecimal(b.toString());
            return b0.add(b1).toString();
        });

        List<Summary> summaryList = new ArrayList<>();
        summaryList.add(sc0);
        summaryList.add(sc1);
        summaryList.add(sc2);

        summarizing(list, summaryInfo, summaryList);
        System.out.println(summaryInfo);

打印结果:

SummaryInfo{minBirthday='1990年12月27日', maxBirthday='1992年11月11日', name='wanghong', minGraduate='2014年06月06日', sumMoney='602.53'}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值