使用Java8新特性:在对象集合里, 对一个属性(集合 )求平均值

需求场景:客服系统的大屏监控页面,展示客服接待量的时分图和折线图,而查询展示的方式有两种:

  1. 单天查询:以小时为单位展示接待量;
  2. java list 求平均值 流式 java集合求平均值_后端

  3. 多天查询:以天为单位展示接待量,没有精确到每天的各个小时;
  4. java list 求平均值 流式 java集合求平均值_后端_02

  5. 新需求是 要在多天查询的基础上进行升级,要求展示 多天且以小时为单位的客服接待量,而数据是选中时间范围内的接待平均值:如下图(对应上图时间范围数据)
  6. java list 求平均值 流式 java集合求平均值_后端_03

代码如下

需求了解以后,这个问题的就出现了,通过一些逻辑代码,我拿到了以小时为单位的多天的数据,但是却是全量的数据,即选中时间范围内,每个客服对应的每天0-23点的数据,3天就==3*24个小时数据;
那么问题来了:如何 去在对象集合里面 对 对象进行去重,且合并对象里的接待量(Map<String ,String> item)属性,并求其平均值?

  1. 对象信息(简化):
private String staffName; //客服名称
	private String groupName; //技能组名称
	private String operationStatus;//查询的属性  1  排队会话数  2  未排队会话数   3 咨询会话数
	private String status;//1-按天,0-按小时
	private Map<String ,String> item = new LinkedHashMap<String ,String>();//key-小时或日期,value-相应日期对应的值
  1. 需要处理的数据格式:
    注意:item属性 中:“2021-11-15-0”:“0” (2021-11-15是日期,第一个0是0点,第二个 0 是接待量)
[
    {
        "staffName":"一级客服A",
        "groupName":"泡泡泡泡",
        "status":"0",
        "item":{
            "2021-11-15-0":"0",
            "2021-11-15-1":"0",
            "2021-11-15-2":"0",
            "2021-11-15-3":"0",
            "2021-11-15-4":"0",
            "2021-11-15-5":"0",
            "2021-11-15-6":"0",
            "2021-11-15-7":"0",
            "2021-11-15-8":"0",
            "2021-11-15-9":"0",
            "2021-11-15-10":"1",
            "2021-11-15-11":"1",
            "2021-11-15-12":"0",
            "2021-11-15-13":"0",
            "2021-11-15-14":"1",
            "2021-11-15-15":"1",
            "2021-11-15-16":"0",
            "2021-11-15-17":"0",
            "2021-11-15-18":"0",
            "2021-11-15-19":"0",
            "2021-11-15-20":"0",
            "2021-11-15-21":"0",
            "2021-11-15-22":"0",
            "2021-11-15-23":"0"
        }
    },
    {
        "staffName":"",
        "groupName":"泡泡泡泡",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"加急客服",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "groupName":"总计",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"一级客服A",
        "groupName":"泡泡泡泡",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"泡泡泡泡",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"加急客服",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "groupName":"总计",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"测试",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"豆子",
        "groupName":"会员中心",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"会员中心",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"泡泡抽盒机",
        "status":"0",
        "item":Object{...}
    },
    {
        "groupName":"总计",
        "status":"0",
        "item":Object{...}
    }
]
  1. 处理代码:
/**
1.customerDatas 需要处理数据集合(客服数据、技能组数据),startDate 和 endDate 是选中的时间范围 如:2021-11-17 - 2021-11-19 3天;
2.因测试环境数据问题,并不是每个客服每天都会有接待数据;
3.因为数据分以每个客服为单位 以及 客服所在技能组为单位,所以会对数据进行区分处理;
3.求得的平均值是以四舍五入并保留两位小数为标准的BigDecimal;
**/

private List<customerData> pressureAverageMethod(List<customerData> customerDatas, String startDate, String endDate) {
   	
   	List<customerData> list = new ArrayList<customerData>();
   	try {
   		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
   		Date start  = sdf.parse(startDate);
   		Date end = sdf.parse(endDate);
   		List<String> listDate = TimeUtil.getBetweenDates(start, end);
   		//用于平均分,==3
   		int num = listDate.size(); 

   		//有数据的技能组名 集合
   		HashMap<String, String> objectObjectHashMap = new HashMap<>( );
   		for (customerData customerData : customerDatas){
   			//获取同一个人的数据
   			if (StringUtil.isNotNull(customerData.getGroupName())){
   				objectObjectHashMap.put(customerData.getGroupName(),customerData.getGroupName());
   			}

   		}
//			logger.info(new Gson().toJson(objectObjectHashMap));

   		//当前数据 有客服名和技能组名
   		ArrayList<customerData> stringArrayAll = new ArrayList<customerData>( );
   		//当前数据 只有技能组名(以技能组分组后数据)
   		ArrayList<customerData> stringArrayOnlyOne= new ArrayList<customerData>( );

   		for (customerData customerData : customerDatas){
   			if (StringUtil.isNotNull(customerData.getStaffName()) &&
   					objectObjectHashMap.containsKey(customerData.getGroupName())){
   				//有客服名和技能组名
   				stringArrayAll.add(customerData);
   			}

   			if ((StringUtil.isNull(customerData.getStaffName()) && objectObjectHashMap.containsKey(customerData.getGroupName()))
   					|| "总计".equals(customerData.getGroupName())){
   				//只有技能组名
   				stringArrayOnlyOne.add(customerData);
   			}
   		}


   		//有客服名和技能组名 逻辑处理开始
   		Map<String,List<customerData>>  userMapAll =  new HashMap<>();
   		stringArrayAll.stream().collect(Collectors.groupingBy(customerData::getStaffName,Collectors.toList()))
   				.forEach(userMapAll::put);

   		userMapAll.forEach((staffName,beanList)->{
   			customerData allBean = new customerData( );
   			allBean.setStaffName(staffName);
   			allBean.setGroupName(beanList.get(0).getGroupName());
   			allBean.setStatus("0");

   			Map<String, String> item = new LinkedHashMap<>();
   			for (customerData bean : beanList){
   				item.putAll(bean.getItem());
   			}

   			Map<String, BigDecimal> item2 = new LinkedHashMap<String, BigDecimal>();
   			for (int i=0; i<24;i++){
   				item2.put(""+i, BigDecimal.valueOf(0.0));
   			}
//				logger.info("pressureAverageMethod item2.size="+item2.size());
   			item.forEach((name,value)->{
   				//Integer.parseInt(name.substring(name.lastIndexOf("-")+1))
   				String substring = name.substring(name.lastIndexOf("-") + 1);
   				if (item2.containsKey(substring)){
   					item2.put(substring, item2.get(substring).add(new BigDecimal(value)));
   				}
   			});
   			item2.forEach((key,value)->{
   				item2.put(key, item2.get(key).divide(BigDecimal.valueOf(num),2, RoundingMode.HALF_UP));
   			});

   			//最后返回 平均数据的 (item)map
   			Map<String, String> itemEnd = new LinkedHashMap<>();
   			item2.forEach((key,value)->{
   				itemEnd.put(key, String.valueOf(value));
   			});
   			allBean.setItem(itemEnd);

   			list.add(allBean);
   		});
   		//有客服名和技能组名 逻辑处理结束


   		//只有技能组名 逻辑处理开始
   		Map<String,List<customerData>>  userMapOnlyOne =  new HashMap<>();
   		stringArrayOnlyOne.stream().collect(Collectors.groupingBy(customerData::getGroupName,Collectors.toList()))
   				.forEach(userMapOnlyOne::put);

   		userMapOnlyOne.forEach((groupName,beanList)->{
   			customerData onlyOneBean = new customerData( );
   			onlyOneBean.setGroupName(groupName);
   			onlyOneBean.setStaffName("");
   			onlyOneBean.setStatus("0");

   			Map<String, String> item = new LinkedHashMap<>();
//				logger.info("csMethod bean="+new Gson().toJson(beanList));
   			for (customerData bean : beanList){
   				item.putAll(bean.getItem());
   			}

   			Map<String, BigDecimal> item2 = new LinkedHashMap<String, BigDecimal>();
   			for (int i=0; i<24;i++){
   				item2.put(""+i, BigDecimal.valueOf(0.0));
   			}
   			item.forEach((name,value)->{
   				String substring = name.substring(name.lastIndexOf("-") + 1);
   				if (item2.containsKey(substring)){
   					item2.put(substring, item2.get(substring).add(new BigDecimal(value)));
   				}
   			});
   			item2.forEach((key,value)->{
   				item2.put(key, item2.get(key).divide(BigDecimal.valueOf(num),2, RoundingMode.HALF_UP));
   			});

   			//最后返回 平均数据的 (item)map
   			Map<String, String> itemEnd = new LinkedHashMap<>();
   			item2.forEach((key,value)->{
   				itemEnd.put(key, String.valueOf(value));
   			});
   			onlyOneBean.setItem(itemEnd);

   			list.add(onlyOneBean);
   		});
   		//只有技能组名 逻辑处理开始
   		
   	} catch (ParseException e) {
   		e.printStackTrace( );
   	}
   	return list;
   }
  1. 最后处理完的数据为:
[
    {
        "staffName":"一级客服A",
        "groupName":"���泡泡泡",
        "status":"0",
        "item":{
            "0":"0.00",
            "1":"0.00",
            "2":"0.00",
            "3":"0.00",
            "4":"0.00",
            "5":"0.00",
            "6":"0.00",
            "7":"0.00",
            "8":"0.00",
            "9":"0.00",
            "10":"0.29",
            "11":"0.29",
            "12":"0.00",
            "13":"0.00",
            "14":"0.00",
            "15":"0.14",
            "16":"0.00",
            "17":"0.14",
            "18":"0.00",
            "19":"0.00",
            "20":"0.00",
            "21":"0.00",
            "22":"0.00",
            "23":"0.00"
        }
    },
    {
        "staffName":"加急客服",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"豆子",
        "groupName":"会员中心",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"泡泡泡泡",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"其他",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"会员中心",
        "status":"0",
        "item":Object{...}
    },
    {
        "staffName":"",
        "groupName":"总计",
        "status":"0",
        "item":Object{...}
    }
]
最后,其实这种数据处理场景 需要用到最核心的代码是 java8的 新特性:stream()方法和collect()方法,有兴趣的朋友可以去找一下专业博客,这些方法用来处理 集合数据很方便实用