-
2021-02-27 09:12:02
需求
想要统计环比指标((本期数量-上期数量)/上期数量*100%) 假设下面是统计9月份的数据 如下所示
品牌
数量
环比
Bosh
1561
311.87%
Siemens
2278
-75.24%
问题
查询的时候 需要同时查询8月的数据 统计出8月的数量 然后才能进行环比指标的计算
{ "count" : 379.0, "brand" : "Bosch", "month" : "2017-08" }
{ "count" : 1561.0, "brand" : "Bosch", "month" : "2017-09" }
{ "count" : 9202.0, "brand" : "Siemens", "month" : "2017-08" }
{ "count" : 2278.0, "brand" : "Siemens", "month" : "2017-09" }
怎么转换得到上图的结果呢? 即
{ "count" : 379.0, "brand" : "Bosch", "month" : "2017-08" }
{ "count" : 1561.0, "brand" : "Bosch", "month" : "2017-09" }
{ "count" : 9202.0, "brand" : "Siemens", "month" : "2017-08" }
{ "count" : 2278.0, "brand" : "Siemens", "month" : "2017-09" }
==>
{ "count" : 1561.0, "brand" : "Bosch", "month" : "2017-09","huanbi": 311.87 }
{ "count" : 2278.0, "brand" : "Siemens", "month" : "2017-09","huanbi":-75.24 }
我以为挺好实现的 没想到还挺折腾的 代码如下
Map record1 = new HashMap(ImmutableMap.of("count", 379, "brand", "Bosch", "month", "2017-08"));
Map record2 = new HashMap(ImmutableMap.of("count", 1561, "brand", "Bosch", "month", "2017-09"));
Map record3 = new HashMap(ImmutableMap.of("count", 9202, "brand", "Siemens", "month", "2017-08"));
Map record4 = new HashMap(ImmutableMap.of("count", 2278, "brand", "Siemens", "month", "2017-09"));
Map record5 = new HashMap(ImmutableMap.of("count", 2278, "brand", "foo", "month", "2017-09"));
List> queryResult = Lists.newArrayList(record1, record4, record3, record2, record5);
// 先按品牌和日期排序
queryResult.sort((o1,o2)->{
int result = 0;
String[] keys = {"brand", "month"};
for (String key : keys) {
String val1 = o1.get(key).toString();
String val2 = o2.get(key).toString();
result = val1.compareTo(val2);
if(result != 0){
return result;
}
}
return result;
});
// 再按品牌分组
Map>> brand2ListMap = queryResult.stream().collect(groupingBy(m -> m.get("brand").toString(), toList()));
/**
* 每组中第一条肯定是上一月的 找到上月的数目
* 第二条记录是本月的 找到本月的数据
* 计算环比 本期记录中添加环比
* 同时删除上一条记录
*/
for (String key : brand2ListMap.keySet()) {
List> recordList = brand2ListMap.get(key);
if (recordList.size() > 1) {
Map prevRecord = recordList.get(0);
Map currentRecord = recordList.get(1);
Integer prevCount = (Integer) prevRecord.get("count");
Integer currentCount = (Integer) currentRecord.get("count");
BigDecimal huanbi = BigDecimal.valueOf((currentCount - prevCount) * 100).divide(BigDecimal.valueOf(prevCount), 2, ROUND_HALF_DOWN);
currentRecord.put("huanbi", huanbi);
recordList.remove(0);
}else{
// 不存在上期记录 环比默认为0
recordList.get(0).put("huanbi", 0);
}
}
// 生成一个新的List 只包含本期记录
List> processedResult = new ArrayList(brand2ListMap.values().stream().flatMap(list->list.stream()).collect(toList()));
// 按照品牌排序
processedResult.sort(Comparator.comparing(o -> o.get("brand").toString()));
processedResult.forEach(System.out::println);
输出结果如下
{count=1561, month=2017-09, brand=Bosch, huanbi=311.87}
{count=2278, month=2017-09, brand=Siemens, huanbi=-75.24}
{count=2278, month=2017-09, brand=foo, huanbi=0}
应该不是我想的复杂了吧?应该没有更简单的方案了吧?
更多相关内容 -
Java 同环比计算相关逻辑
2021-05-25 21:16:02Java 同环比计算相关逻辑相关概念背景实现思路具体代码SQL实现方式[Mysql]按月进行分组同比 2022年/2020年各月数据同比按月进行分组同比 各月数据环比 相关概念 「同比」 与历史「同时期]比较,例如2011年3月份与...相关概念
「同比」
与历史「同时期]比较,例如2011年3月份与2010年3月份相比,叫「同比」。
同比是“同期”的比较,中间有可能跨了若干个统计周期,或者没有跨越一个统计周期。跨越了若干个统计周期的同比与环比不一样,而一个统计周期也没有跨越的同比实际上与环比是一样的
同比是“同期”的比较,中间有可能跨了若干个统计周期,或者没有跨越一个统计周期。跨越了若干个统计周期的同比与环比不一样,而一个统计周期也没有跨越的同比实际上与环比是一样的
「环比」
与「上一个」统计周期比较,例如2011年4月份与2011年3月份相比较,称为「环比」。
本期环比增长(下降)率(%) = (本期价格/上期价格 — 1 )× 100%
本期同比增长(下降)率(%) = (本期价格/上年同期价格 —1) × 100%背景
项目中使用了不同种数据库,为了减少工作量,不在数据库层进行同环比计算(需要查看不同数据库函数语法).所以决定在代码层面实现
实现思路
使用标记,或者缓冲避免多次循环数据
环比
1.降序排序
2.环比计算
循环结果集(不连续时间区间)
取标记位数据(标记位默认为1)使用下标
根据日期判断是不是相邻区间
如果是->直接计算,标志位➕1
如果不是->结果为0,标志位不变
时间复杂度O(n)同比
1.升序排序
2.同比计算(不连续时间区间)
设置缓冲时间区间数据List<Map(以年,不同月为key)>
与缓冲区间判断年是否是相邻年(默认比较相邻年)
如果是->取对应的月数据
取到数据,计算
取不到,结果为0
如果不是->本年度所有月同比为0
时间复杂度为O(n)具体代码
方法无法直接使用,需要结合自己逻辑改进
private List<Map<String, Object>> momYoyData(List<Map<String, Object>> obj,QueryDataSetBo bo){ Map<String, Object> momCOUNTSet = bo.getMomCOUNTSet(); //时间字段 String fieldName = (String)momCOUNTSet.get("fieldName"); String timeFieldKey=null; //时间字段类型【年,月,日,周,季,半年度】 int type=(int)momCOUNTSet.get("type"); switch (type){ case 1: timeFieldKey="date_format(column, '%Y')".replace("column",fieldName); break; case 2: timeFieldKey="date_format(column, '%Y-%m')".replace("column",fieldName); break; case 3: timeFieldKey="date_format(column, '%Y-%m-%d')".replace("column",fieldName); break; case 4: timeFieldKey="date_format(column,'%Y-%u')".replace("column",fieldName); break; case 5: timeFieldKey="concat(date_format(column, '%Y'),'-',FLOOR((date_format(column, '%m')+2)/3))".replace("column",fieldName); break; case 6: timeFieldKey="concat(date_format(column, '%Y'),'-',CEIL((date_format(column, '%m'))/6))".replace("column",fieldName); break; default: break; } //数据字段 List<Map<String, Object>> dataFieldName = (List<Map<String, Object>>)momCOUNTSet.get("dataFieldName"); ArrayList<String> yoyfieldList = new ArrayList<>(); //同比字段list ArrayList<String> momfieldList = new ArrayList<>(); //环比字段list for (Map<String, Object> stringObjectMap : dataFieldName) { String value = String.valueOf(stringObjectMap.get("value")); String compute = String.valueOf(stringObjectMap.get("compute")); String dataFieldkey=value+"_"+compute; if ((int)stringObjectMap.get("momYoyType")==1){ //同比 yoyfieldList.add(dataFieldkey); }else if ((int)stringObjectMap.get("momYoyType")==2){ //环比 momfieldList.add(dataFieldkey); } } //同比 //升序 List<Map<String, Object>> yoyDataList =new ArrayList<>(); List<Map<String, Object>> maps =new ArrayList<>(obj); String finalTimeFieldKey=timeFieldKey; Collections.sort(maps, new Comparator<Map<String, Object>>() { @Override public int compare(Map<String, Object> o1, Map<String, Object> o2) { String o11 = (String)o1.get(finalTimeFieldKey); String o22 = (String)o2.get(finalTimeFieldKey); return o11.compareTo(o22); } }); if (yoyfieldList!=null&&yoyfieldList.size()>0){ Map<String, Object> bufferMap = new HashMap<>(); for (int i = 0; i < maps.size(); i++) { Map<String, Object> newMap=new HashMap<>(); Map<String, Object> map=maps.get(i); newMap.putAll(map); String time = (String) map.get(finalTimeFieldKey); String[] split = time.split("-"); String year=split[0]; String time2=split[1]; String lastYear = getLastYear(year); if (bufferMap.containsKey(lastYear)&&bufferMap.get(lastYear)!=null){ HashMap<String, Object > dataMap = (HashMap<String, Object>)bufferMap.get(lastYear); for (String yoyfield : yoyfieldList) { if (dataMap.containsKey(time2)||dataMap.get(time2)!=null){ Map<String, Object> databufferMap = (Map<String, Object>)dataMap.get(time2); if (map.containsKey(yoyfield)&&map.get(yoyfield)!=null&&databufferMap.containsKey(yoyfield)&&databufferMap.get(yoyfield)!=null){ BigDecimal p = new BigDecimal((Double) map.get(yoyfield)); BigDecimal q = new BigDecimal((Double) databufferMap.get(yoyfield)); BigDecimal rate = new BigDecimal(0.000000); rate=(p).divide(q,3, RoundingMode.HALF_UP); newMap.put(yoyfield+"_"+"yoy",Double.valueOf(rate.toString())); }else { newMap.put(yoyfield+"_"+"yoy",0); } }else { newMap.put(yoyfield+"_"+"yoy",0); } } }else { for (String yoyfield : yoyfieldList) { newMap.put(yoyfield+"_"+"yoy",0); } } yoyDataList.add(newMap); //操作缓冲MaP if (i==0){ Map<String, Object> dataMap=new HashMap<>(); dataMap.put(time2,map); bufferMap.put(year,dataMap); }else{ if (bufferMap.containsKey(year)&&bufferMap.get(year)!=null){ HashMap<String, Object > dataMap = (HashMap<String, Object>)bufferMap.get(year); dataMap.put(time2,map); bufferMap.put(year,dataMap); }else { Map<String, Object> dataMap=new HashMap<>(); dataMap.put(time2,map); bufferMap.put(year,dataMap); } } } } //环比 //升序 List<Map<String, Object>> maps2 =new ArrayList<>(obj); Collections.sort(maps2, new Comparator<Map<String, Object>>() { @Override public int compare(Map<String, Object> o1, Map<String, Object> o2) { String o11 = (String)o1.get(finalTimeFieldKey); String o22 = (String)o2.get(finalTimeFieldKey); return o22.compareTo(o11); } }); List<Map<String, Object>> momDataList =new ArrayList<>(); if (momfieldList!=null&&momfieldList.size()>0){ for (int i = 0; i < maps2.size(); i++) { Map<String, Object> map=maps2.get(i); Map<String, Object> newMap=new HashMap<>(); newMap.putAll(map); if (i==maps2.size()-1){ for (String momfield : momfieldList) { newMap.put(momfield+"_"+"mom",0); } }else { Map<String, Object> nextMap=maps2.get(i+1); String time = (String) map.get(finalTimeFieldKey); String nextTime = (String) nextMap.get(finalTimeFieldKey); if (isContinuous(time,nextTime,type)) { for (String momfield : momfieldList) { if (map.containsKey(momfield)&&map.get(momfield)!=null&&nextMap.containsKey(momfield)&&nextMap.get(momfield)!=null){ BigDecimal p = new BigDecimal((Double) map.get(momfield)); BigDecimal q = new BigDecimal((Double) nextMap.get(momfield)); BigDecimal rate = new BigDecimal(0.000000); rate=(p).divide(q,3, RoundingMode.HALF_UP); newMap.put(momfield+"_"+"mom",Double.valueOf(rate.toString())); }else { newMap.put(momfield+"_"+"mom",0); } } }else { for (String momfield : momfieldList) { newMap.put(momfield+"_"+"mom",0); } } } momDataList.add(newMap); } } obj.addAll(momDataList); obj.addAll(yoyDataList); List<Map<String, Object>> merge = merge(obj, timeFieldKey); Collections.sort(merge, new Comparator<Map<String, Object>>() { @Override public int compare(Map<String, Object> o1, Map<String, Object> o2) { String o11 = (String)o1.get(finalTimeFieldKey); String o22 = (String)o2.get(finalTimeFieldKey); return o11.compareTo(o22); } }); return merge; } private String getLastYear(String year){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy"); try { Date parse = simpleDateFormat.parse(year); Calendar cal=Calendar.getInstance(); cal.setTime(parse); cal.add(Calendar.YEAR,-1); Date time = cal.getTime(); return simpleDateFormat.format(time); } catch (ParseException e) { return null; } } private String getlastDay(String daystr){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date parse = simpleDateFormat.parse(daystr); Calendar c = Calendar.getInstance(); c.setTime(parse); int day=c.get(Calendar.DATE); c.set(Calendar.DATE,day-1); return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()); } catch (Exception e) { return null; } } private boolean isContinuous(String time,String nextTime,Integer type){ boolean isContinuous=false; String[] split = time.split("-"); String yearTime=split[0]; String timeTime=split[1]; String[] split2 = nextTime.split("-"); String yearNextTime=split2[0]; String timeNextTime=split2[1]; switch (type){ case 1: if (yearNextTime.equals(getLastYear(yearTime))){ isContinuous=true; } break; case 2: if (yearTime.equals(yearNextTime)){ if (Integer.valueOf(timeTime)-Integer.valueOf(timeNextTime)==1){ isContinuous=true; } }if (yearNextTime.equals(getLastYear(yearTime))){ if (Integer.valueOf(timeTime)==1&&Integer.valueOf(timeNextTime)==12){ isContinuous=true; } } break; case 3: if (getlastDay(time).equals(nextTime)){ isContinuous=true; } break; case 4: if (yearTime.equals(yearNextTime)){ if (Integer.valueOf(timeTime)-Integer.valueOf(timeNextTime)==1){ isContinuous=true; } }if (yearNextTime.equals(getLastYear(yearTime))){ if ((Integer.valueOf(timeTime)==1&&Integer.valueOf(timeNextTime)!=0&&(Integer.valueOf(timeNextTime)==52||Integer.valueOf(timeNextTime)==53)) ||(Integer.valueOf(timeTime)==0&&(Integer.valueOf(timeNextTime)==52||Integer.valueOf(timeNextTime)==53)) ){ isContinuous=true; } } break; case 5: if (yearTime.equals(yearNextTime)){ if (Integer.valueOf(timeTime)-Integer.valueOf(timeNextTime)==1){ isContinuous=true; } }if (yearNextTime.equals(getLastYear(yearTime))){ if (Integer.valueOf(timeTime)==1&&Integer.valueOf(timeNextTime)==4){ isContinuous=true; } } break; case 6: if (yearTime.equals(yearNextTime)){ if (Integer.valueOf(timeTime)-Integer.valueOf(timeNextTime)==1){ isContinuous=true; } }if (yearNextTime.equals(getLastYear(yearTime))){ if (Integer.valueOf(timeTime)==1&&Integer.valueOf(timeNextTime)==2){ isContinuous=true; } } break; default: break; } return isContinuous; } public static List<Map<String, Object>> merge(List<Map<String, Object>> m1,String mergeKey){ Set<String> set = new HashSet<>(); System.out.println("m1的数据格式是:"+m1); return m1.stream() .filter(map->map.get(mergeKey)!=null) .collect(Collectors.groupingBy(o->{ //暂存所有key set.addAll(o.keySet()); //按mergeKey分组 return o.get(mergeKey).toString(); })) .entrySet().stream().map(o->{ //合并 Map<String, Object> map = o.getValue().stream().flatMap(m->{ return m.entrySet().stream(); }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a,b)->b)); //为没有的key赋值0 set.stream().forEach(k->{ if(!map.containsKey(k)) map.put(k, 0); }); return map; }).collect(Collectors.toList()); }
SQL实现方式[Mysql]
-- 年【普通年】/【闰年】 SELECT date_format(time1, '%Y'), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY date_format(time1, '%Y') -- 月【普通年】/【闰年】 SELECT date_format(time1, '%Y-%m'), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY date_format(time1, '%Y-%m') -- 日【普通年】/【闰年】 SELECT date_format(time1, '%Y-%m-%d'), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY date_format(time1, '%Y-%m-%d') -- 季度 【普通年】/【闰年】 SELECT concat(date_format(time1, '%Y'),'--',FLOOR((date_format(time1, '%m')+2)/3)), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY concat(date_format(time1, '%Y'),'--',FLOOR((date_format(time1, '%m')+2)/3)) -- 半年度 【普通年】/【闰年】 SELECT concat(date_format(time1, '%Y'),'--',CEIL((date_format(time1, '%m'))/6)), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY concat(date_format(time1, '%Y'),'--',CEIL((date_format(time1, '%m'))/6)) -- 周 【普通年】/【闰年】 SELECT DATE_FORMAT(time1,'%Y%u'), round( sum( time1_data ) / 1, 1 ) FROM time_test WHERE time1 is not null GROUP BY DATE_FORMAT(time1,'%Y%u')
按月进行分组同比 2022年/2020年各月数据同比
-- 按月进行分组同比 2022年/2020年各月数据同比 SELECT a1.time, a1.`month`, ifnull(round(a1.`DATA`/b1.`DATA`,2),0) AS 同比 FROM ( -- 2022年各月数据 SELECT time, `DATA`, SUBSTRING_INDEX(time,"-",-1) AS `month` from ( SELECT date_format(time1, '%Y-%m') AS time, round( sum( time1_data ) / 1, 1 ) AS `DATA` FROM time_test WHERE time1 is not null AND date_format(time1, '%Y')='2022' GROUP BY date_format(time1, '%Y-%m') ) a ) a1 LEFT JOIN ( -- 2020年各月数据 SELECT time, `DATA`, SUBSTRING_INDEX(time,"-",-1) AS `month` from ( SELECT date_format(time1, '%Y-%m') AS time, round( sum( time1_data ) / 1, 1 ) AS `DATA` FROM time_test WHERE time1 is not null AND date_format(time1, '%Y')='2020' -- 非连续性数据 AND date_format(time1, '%Y-%m') !='2020-05' GROUP BY date_format(time1, '%Y-%m') ) b ) b1 ON a1.`month`=b1.`month`
按月进行分组同比 各月数据环比
SELECT a1.time, b1.time, ifnull(round(a1.`DATA`/b1.`DATA`,2),0) AS 环比, a1.`DATA`, b1.`DATA` FROM ( SELECT time, `DATA`, SUBSTRING_INDEX(time,"-",1) AS `year`, SUBSTRING_INDEX(time,"-",-1) AS `month` from ( SELECT date_format(time1, '%Y-%m') AS time, round( sum( time1_data ) / 1, 1 ) AS `DATA` FROM time_test WHERE time1 is not null GROUP BY date_format(time1, '%Y-%m') ) a ) a1 LEFT JOIN ( SELECT time, `DATA`, SUBSTRING_INDEX(time,"-",1) AS `year`, SUBSTRING_INDEX(time,"-",-1) AS `month` from ( SELECT date_format(time1, '%Y-%m') AS time, round( sum( time1_data ) / 1, 1 ) AS `DATA` FROM time_test WHERE time1 is not null GROUP BY date_format(time1, '%Y-%m') ) b ) b1 ON a1.`year`=b1.`year` AND a1.`month`=b1.`month`+1 ORDER BY a1.time desc
-
Java计算同比环比
2020-08-31 14:39:28Java计算同比环比 同比环比计算基本概念和计算公式 同比率:本年数据比上一年数据增长或减少的比率 同比率计算公式:rate = (本年数据 - 前一年数据) / 前一年数据 实例:2020年10月游客数量为80W,2019年10月游客...Java计算同比环比
同比环比计算基本概念和计算公式
同比率:本年数据比上一年数据增长或减少的比率
同比率计算公式:rate = (本年数据 - 前一年数据) / 前一年数据
实例:2020年10月游客数量为80W,2019年10月游客数量为100W,2018年10月游客数量为90W
2020年同比率为:rate :(80 - 100)/100 * 100%= -20%
2019年同比率为:rate :(100 - 900)/900 * 100%= +11%
(“+” 为增长,“-”为降低)环比率:本月(季度)数据比上个月(季度)数据增长或减少的比率
环比率计算公式:rate = (本月数据 - 上个月数据) / 上个月数据
实例:2020年10月游客数量为100W,2020年9月游客数量为90W,2020年7月游客数量为80W
2020年10月同比率为:rate :(100 - 90)/90 * 100%= +11%
2019年10月同比率为:rate :(90- 80)/800 * 100%= +12.5%
注:同比环比计算公式是相同的,但计算数据对应的时间是不同的代码实现逻辑
通过Calendar等时间函数和HashMap,[ hashmap(key,value) key为时间,value为该时间对应的值]。将key和value一一对应的存入集合中,通过对key进行操作,再用key获取HashMap中相对应的value,套公式计算(重点在于对时间(key)的操作,通过key可直接获取value进行计算)
详细逻辑步骤
首先通过SQL语句获取数据库中相应的时间和该时间对应的数据,按时间分组排序
SELECT DATAS.DATE AS NAME , SUM( DATAS.VISITORSUM) AS VALUE, 2 AS sfzj, '' AS bfb FROM (SELECT TOURIST.* ,CONCAT(YEAR,'年',QUARTER,'月') AS DATE FROM TOURISTFLOW TOURIST)DATAS GROUP BY DATAS.DATE ORDER BY DATAS.DATE
接着设置时间范围,将最早的时间减去一年设为最小时间,最后的时间为最大时间,以此为范围即可保证覆盖所有数据
// 设置时间范围 // 获取最前的时间的第一个列表 analyzeBean firstTimeSubway = analyzeByYear.get(0); String startTime = firstTimeSubway.getTime(); // 获取最后时间的最后一个列表 analyzeBean endTimeSubway = analyzeByYear.get(analyzeByYear.size() - 1); String endTime = endTimeSubway.getTime(); // 时间格式转换 SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月"); Date parse = format.parse(startTime); Date parse1 = format.parse(endTime); Calendar c = Calendar.getInstance(); c.setTime(parse); c.add(Calendar.YEAR, -1); Date y = c.getTime(); // 获取最前的时间的前一年的时间作为查询范围 String firstTime = format.format(y); analyzeRequestBean.setStartTime(firstTime); Calendar c1 = Calendar.getInstance(); c1.setTime(parse1); Date y1 = c1.getTime(); // 获取最后一年的时间作为查询范围 String lastTime = format.format(y1); analyzeRequestBean.setStartTime(lastTime);
在将所有数据的结果集存入HashMap中 hash(key,value) key为时间,value为数据值
hashMap.put(time, analyzeByYear.get(i).getValue());
最后通过for循环和CaleCndar函数和Date函数对时间(key)进行相应的操作,再通过时间(key)到HashMap中找对应的值进行计算
for (int i = 0; i < analyzeByYear.size(); i++) { AnalyzeBean analyzeBean = analyzeByYear.get(i); if (i == 0) { // 是否增长("0:降低 1:增加 2:既不增长也不降低") analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } else { SimpleDateFormat format2 = new SimpleDateFormat("yyyy年MM月"); // 当前数据 Date parse2 = format2.parse(analyzeBean.getTime()); Calendar c2 = Calendar.gaetInstance(); c2.setTime(parse2); c2.add(Calendar.YEAR, 0); Date t = c2.getTime(); String time = format2.format(t); Integer value = hashMap.get(time); // 往年数据 Date parse3 = format2.parse(time); Calendar c3 = Calendar.getInstance(); c3.setTime(parse3); c3.add(Calendar.YEAR, -1); Date year = c3.getTime(); String time1 = format2.format(year); Integer value1 = hashMap.get(time1); if (null != value1 && null != value) { if (value.equals(value1)) { analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } else { if (value > value1) { analyzeBean.setSfzj(1); } else { analyzeBean.setSfzj(0); } // 2个值减法 绝对值 int abs = Math.abs(value - value1); float a = (float) (abs) / (float) value1 * 100; analyzeBean.setBfb(a + ""); } } else { analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } } }
同比实例代码:
// 求同比 @Override public Result getAnalyzeByYear(AnalyzeRequestBean analyzeRequestBean) { try { // 检查参数 if (null == analyzeRequestBean) { return ResultUtil.fail(ResultEnum.PARAMS_ERROR); } a List<AnalyzeBean> analyzeByYear = InfoMapper.getAnalyzeByYear(analyzeRequestBean); if (analyzeByYear == null || analyzeByYear.size() == 0) { return ResultUtil.ok(null); } // 设置时间范围 // 获取最前的时间的第一个列表 analyzeBean firstTimeSubway = analyzeByYear.get(0); String startTime = firstTimeSubway.getTime(); // 获取最后时间的最后一个列表 analyzeBean endTimeSubway = analyzeByYear.get(analyzeByYear.size() - 1); String endTime = endTimeSubway.getTime(); // 时间格式转换 SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月"); Date parse = format.parse(startTime); Date parse1 = format.parse(endTime); Calendar c = Calendar.getInstance(); c.setTime(parse); c.add(CaleCndar.YEAR, -1); Date y = c.getTime(); // 获取最前的时间的前一年的时间作为查询范围 String firstTime = format.format(y); analyzeRequestBean.setStartTime(firstTime); Calendar c1 = Calendar.getInstance(); c1.setTime(parse1); Date y1 = c1.getTime(); // 获取最后一年的时间作为查询范围 String lastTime = format.format(y1); analyzeRequestBean.setStartTime(lastTime); // 把大范围的结果集都放入hashMap中 HashMap<String, Integer> hashMap = new HashMap<>(); for (int i = 0; i < analyzeByYear.size(); i++) { analyzeBean analyzeBean = analyzeByYear.get(i); SimpleDateFormat format1 = new SimpleDateFormat("yyyy年MM月"); Date parse2 = format1.parse(analyzeBean.getTime()); Calendar c2 = Calendar.getInstance(); c2.setTime(parse2); c2.add(Calendar.YEAR, 0); Date t = c2.getTime(); String time = format1.format(t); hashMap.put(time, analyzeByYear.get(i).getValue()); } for (int i = 0; i < analyzeByYear.size(); i++) { AnalyzeBean analyzeBean = analyzeByYear.get(i); if (i == 0) { // 是否增长("0:降低 1:增加 2:既不增长也不降低") analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } else { SimpleDateFormat format2 = new SimpleDateFormat("yyyy年MM月"); // 当前数据 Date parse2 = format2.parse(analyzeBean.getTime()); Calendar c2 = Calendar.gaetInstance(); c2.setTime(parse2); c2.add(Calendar.YEAR, 0); Date t = c2.getTime(); String time = format2.format(t); Integer value = hashMap.get(time); // 往年数据 Date parse3 = format2.parse(time); Calendar c3 = Calendar.getInstance(); c3.setTime(parse3); c3.add(Calendar.YEAR, -1); Date year = c3.getTime(); String time1 = format2.format(year); Integer value1 = hashMap.get(time1); if (null != value1 && null != value) { if (value.equals(value1)) { analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } else { if (value > value1) { analyzeBean.setSfzj(1); } else { analyzeBean.setSfzj(0); } // 2个值减法 绝对值 int abs = Math.abs(value - value1); float a = (float) (abs) / (float) value1 * 100; analyzeBean.setBfb(a + ""); } } else { analyzeBean.setSfzj(2); analyzeBean.setBfb(null); } } } return ResultUtil.ok(analyzeByYear); } catch (ParseException ex) { ex.printStackTrace(); } return ResultUtil.ok(null); }
环比类似,只是把c.add(Calendar.YEAR, 0);换成c.add(Calendar.MONTH, 0)
实现逻辑其实不难,只是我写复杂了,如有更好的方法欢迎留言交流讨论
-
java计算同比和环比
2021-12-02 10:13:04@java计算同比和环比 同比和环比的概念 同比和环比的区别:同比是不连续的两期数据做对比;环比是两期连续数据做对比。计算方式:环比增长率=(本期数-上期数)/上期数×100%;同比增长率=(本期数-同期数)÷同期数×...@java计算同比和环比
同比和环比的概念
同比和环比的区别:
同比是不连续的两期数据做对比;环比是两期连续数据做对比。计算方式:环比增长率=(本期数-上期数)/上期数×100%;同比增长率=(本期数-同期数)÷同期数×100%;同比更加侧重反映长期的大趋势,环比会突出显示数据的短期趋势。计算基准
根据计算的基准不同,可分为周环比,月环比,日环比,周同比,月同比,日同比等,代入到上面的公式,以月为例,
月环比增长率=(本月数-上月数)/上月数
月同比增长率=(本月数-去年本月数)/ 去年本月数java 通用方法
因此需要根据基准单位的不同去向前推对应单位的日期。
本方法依次传入现在的日期,前推的数量,前推的单位,执行后将计算的数据以Data类型返回/** * 获得指定日期之前一段时期的日期。例如某日期之前3天的日期等。 * * @param origDate * 基准日期 * @param amount * 时间数量 * @param timeUnit * 时间单位,如年、月、日等。用Calendar中的常量代表, * Calendar.YEAR-年 * Calendar.MONTH-月 * Calendar.DATE-日 * @return {@link Date} */ public static Date dateBefore(Date origDate, int amount, int timeUnit) { Calendar calendar = Calendar.getInstance(); calendar.add(timeUnit, -amount); return calendar.getTime(); }
可能会有向后推算日期的场景,所以在此将负号变成正,即完成了对此方法的更改。
/** * 获得指定日期之后一段时期的日期。例如某日期之后3天的日期等。 * * @param origDate * 基准日期 * @param amount * 时间数量 * @param timeUnit * 时间单位,如年、月、日等。用Calendar中的常量代表, * Calendar.YEAR-年 * Calendar.MONTH-月 * Calendar.DATE-日 * @return {@link Date} */ public static Date dateAfter(Date origDate, int amount, int timeUnit) { Calendar calendar = Calendar.getInstance(); calendar.add(timeUnit, amount); return calendar.getTime(); }
代码验证实例。
import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; public class DataCount { /** * 获得指定日期之前一段时期的日期。例如某日期之前3天的日期等。 * * @param origDate * 基准日期 * @param amount * 时间数量 * @param timeUnit * 时间单位,如年、月、日等。用Calendar中的常量代表, * Calendar.YEAR-年 * Calendar.MONTH-月 * Calendar.DATE-日 * @return {@link Date} */ public static Date dateBefore(Date origDate, int amount, int timeUnit) { Calendar calendar = Calendar.getInstance(); calendar.add(timeUnit, -amount); return calendar.getTime(); } /** * 获得指定日期之后一段时期的日期。例如某日期之后3天的日期等。 * * @param origDate * 基准日期 * @param amount * 时间数量 * @param timeUnit * 时间单位,如年、月、日等。用Calendar中的常量代表, * Calendar.YEAR-年 * Calendar.MONTH-月 * Calendar.DATE-日 * @return {@link Date} */ public static Date dateAfter(Date origDate, int amount, int timeUnit) { Calendar calendar = Calendar.getInstance(); calendar.add(timeUnit, amount); return calendar.getTime(); } public static void main(String[] args) { DateFormat df1 = DateFormat.getDateInstance();//日期格式,精确到日 System.out.println("计算前置日期前"); Date date1 = new Date(); DateFormat YEAR_FORMAT = new SimpleDateFormat("yyyy"); DateFormat MONTH_FORMAT = new SimpleDateFormat("MM"); DateFormat Day_FORMAT = new SimpleDateFormat("dd"); System.out.println(YEAR_FORMAT.format(date1)); System.out.println(MONTH_FORMAT.format(date1)); System.out.println(Day_FORMAT.format(date1)); System.out.println(df1.format(date1)); System.out.println(date1); System.out.println("计算前置日期后"); Date date = dateBefore(date1, 1, Calendar.DATE); System.out.println(YEAR_FORMAT.format(date)); System.out.println(MONTH_FORMAT.format(date)); System.out.println(Day_FORMAT.format(date)); System.out.println(date); System.out.println(df1.format(date)); System.out.println("计算后置日期后"); Date dateAfter = dateAfter(date1, 1, Calendar.DATE); System.out.println(YEAR_FORMAT.format(dateAfter)); System.out.println(MONTH_FORMAT.format(dateAfter)); System.out.println(Day_FORMAT.format(dateAfter)); System.out.println(dateAfter); System.out.println(df1.format(dateAfter)); } }
输出结果截图
-
java处理环比增长率
2020-08-18 16:32:37公式:环比增长率=(当月数据-上月数据)/上月数据 第一步首先统计出某年12个月+上年最后一个月份的数据,sql如下: SELECT a.`month` AS `month`, ifnull( b.winOrderNum, 0 ) as winOrderNum, ifnull( b.... -
java 根据输入的两个数值计算日环比-代码示例
2019-09-05 11:14:29公式:(本期数量-上期数量)/上期数量*100%) 代码: public static void main(String[] args) { Integer bcount = 119; // 本期数量 Integer scount = 158; // 上期数量 BigDecimal tests = BigDecimal.... -
java时间计算同比环比周的问题
2020-03-18 17:16:232、同时需要计算对应的去年同比时间和环比(就是上一个时间段,周的2020-03环比就是2020-04)时间, 3、同时还要获取周和月的开始时间和结束时间,比如周2020-02的开始是2020-01-06,结束时间是2020-01-12, 4、周... -
数据相关概念同比,环比
2021-02-27 20:49:10环比,则相对更简单,就是相邻时间段的对比,不象同比那样,是在相邻时间段内部的某个相同时间点的对比; 如图所示,14年4月和14年3月是相邻时间段,这两个时间段的数据都比,就是环比; 当然我们也可以把13年全年... -
使用mapreduce计算环比的实例
2021-03-03 12:46:00最近做了一个小的mapreduce程序,...首先解释下环比,例如我们要算本周的环比,那么计算方式就是本周的数据和上周数字的差值除以上周数值就是环比了,如果是月的环比就是本月和上月数据的差值除以上月数字就是本月... -
计算同比和环比增长率
2021-02-27 09:12:00@RequiresPermissions("analysis:analysis:smartSearch")@RequestMapping(value= "/analysis/analysis/smartSearch")publicString smartSearch(){Page page = new Page(request, response);//page.setPageSize( 25 )... -
java实现各种数据统计图(柱形图,饼图,折线图)
2020-08-30 22:01:14java 柱形图 饼图 折线图 JFreeChart,里面包含与JFreeChart有关的所有jar包,还有我自己写的例子,通俗易懂! -
java 计算同比增长工具类
2019-08-06 17:50:58java计算同比增长率的工具类 为了数据的严谨性,统一装换为BigDecimal,话不多说,看代码。 欢迎大家加群 进行讨论 qq群:714398799 package com.pig4cloud.pigx.admin.api.util; import java.math.BigDecimal; ... -
Java报表软件--如何在报表系统Style Report中制作环比数据图
2021-02-25 19:17:52环比数据是指与同年的上一期相比的数据。如果做的是周数据比较,环比就是本周数据比上周的数据;如果做的是月数据比较,环比就是本月数据比上月的数据;如果做的是季数据比较,环比就是本季数据比上季的数据。对于... -
Java程序员的日常—— 基于类的策略模式、List与List、泛型编译警告、同比和环比
2021-02-27 09:12:08早晨起得太早,昨晚睡得太晚,一天都迷迷糊糊的。中午虽然睡了半个小时,可是依然没有缓过来。...effective java 通过函数来作为策略通过函数作为策略有两个要注意的地方:使用接口作为策略传入如果长... -
Java判断无向图中是否存在环
2020-12-21 17:00:23第一次写博客,不太会用,话不多说 直接上代码 详细可以看注释,无向图判断是否存在环比有向图相对复杂一点 ,需要判断访问的节点的临接表中的节点与父节点是否相同。 /** * @Description:判断无向图是否有环 深度...