有一个同事写的一个项目,因为手上比较忙,让我临时帮忙,需要做的事情是这样的:数据库中某个字段值存的是Json字符串,这其中包含了问卷信息Json,我需要统计其中选项的累计票数,按道理而言,不是很难,但是我拿到了项目,还是有一瞬间愣神,比如该字段值的字符串如下:
[{
"title": "您最喜欢的社团",
"type": 0,
"selects": [{
"value": "轮滑社"
}, {
"value": "篮球协会"
}, {
"value": "羽毛球社"
}, {
"value": "辩论社"
}],
"selected": [1]
}, {
"title": "长度的单位",
"type": 1,
"selects": [{
"value": "m"
}, {
"value": "km"
}, {
"value": "kg"
}, {
"value": "cm"
}, {
"value": "℃"
}, {
"value": "㎡"
}],
"selected": [0, 2, 3]
}, {
"title": "文本题-------------------------------------------------------------------------------------------------",
"type": 2,
"value": "测试",
"isRequire": true
}]
其中,type为0表示单选,type为1表示多选,type为2表示文本题不统计,要做的就是统计每个选项的累计结果,比如现在有3条问卷记录,我们进行统计:
由于设计原因,也来不及更改,我的打算是先封装一个选项初始化的方法,其对应的value值(结果)初始化为0,代码如下:
public class AnswerInit {
String title;
String key;
int value;
//getter和setter略
}
/**
* 结果集初始化
*/
public List<AnswerInit> answerResultInit(QueAnswer que) {
if (StringUtils.isEmpty(que.getPaperId())) {
log.error("问卷Id为null!");
return null;
}
List<QueAnswer> resultAnswer = queAnswerService.select(que);
QueAnswer queAnswer = resultAnswer.get(0);
/**获取作答结果 解析为Json进行选项初始化 */
List<AnswerContentVo> answerContentVoList = null;
try {
answerContentVoList = JSONArray.parseArray(queAnswer.getAnswerContent(), AnswerContentVo.class);
} catch (Exception e) {
log.error("字符串转对象失败|失败原因=" + e.getMessage());
return null;
}
List<AnswerInit> answerInits = new ArrayList<>();
for (AnswerContentVo answerContentVo : answerContentVoList) {
Integer type = answerContentVo.getType();
List<Selects> selectsList = answerContentVo.getSelects();
if (type == 2) {
log.error("该类型不需要初始化!");
continue;
} else {
for (Selects se : selectsList) {
AnswerInit answerInit = new AnswerInit();
answerInit.setTitle(answerContentVo.getTitle());
answerInit.setKey(se.getValue().toString());
answerInit.setValue(0);
answerInits.add(answerInit);
}
}
}
return answerInits;
}
/** 字段值转对象 */
public class AnswerContentVo {
private String title;
private Integer type;
private List<Selects> selects;
private String[] selected;
//getter和setter方法略
}
//controller方法如:
@RequestMapping("/ans1003")
// @mtgLog(matterName = "答题结果统计")
String questionAnswerCount(@RequestBody String reqStr, HttpServletRequest request) {
QueAnswer reqVo = new InfoReqUtil().returnBean("答题结果统计", reqStr, QueAnswer.class);
if (StringUtils.isEmpty(reqVo.getPaperId())) {
log.error("问卷id不能为空!");
return ResponseWrap.failure("问卷id不能为空!");
}
List<AnswerInit> mapInit = queAnswerService.answerResultInit(reqVo);
log.info("计算前初始化=" + JSON.toJSONString(mapInit));
List<QueAnswer> resultAnswer = queAnswerService.select(reqVo);
if (resultAnswer.isEmpty()) {
return ResponseWrap.failure("暂时没有问卷答案信息");
} else {
for (QueAnswer queAnswer : resultAnswer) {
/**获取作答结果 解析为Json进行统计 统计结果返显Web */
List<AnswerContentVo> answerContentVoList = null;
try {
answerContentVoList = JSONArray.parseArray(queAnswer.getAnswerContent(), AnswerContentVo.class);
} catch (Exception e) {
log.error("字符串转对象失败|失败原因=" + e.getMessage());
return ResponseWrap.failure("问卷答案信息非Json字符串");
}
for (AnswerContentVo answerContentVo : answerContentVoList) {
if (answerContentVo.getType() == 2) {
continue;
}
String title = answerContentVo.getTitle();
List<Selects> selectsList = answerContentVo.getSelects();
log.info("selected=============" + Arrays.toString(answerContentVo.getSelected()));
String[] selectedStr = answerContentVo.getSelected();
for (int i = 0; i < selectedStr.length; i++) {
// for (AnswerInit an : mapInit) {
for (int n = 0; n < mapInit.size(); n++) {
if (title.equals(mapInit.get(n).getTitle())) {
if (selectsList.get(Integer.valueOf(selectedStr[i])).getValue().equals(mapInit.get(n).getKey())) {
mapInit.get(n).setValue(mapInit.get(n).getValue() + 1);
mapInit.set(n, mapInit.get(n));
}
}
}
}
}
}
}
log.info("计算后结果=" + JSON.toJSONString(mapInit));
return JSON.toJSONString(mapInit);
}
调用方法,打印日志,验证了一下结果,满足要求,虽然结果正确,但是看源码不难发现for已经是4层嵌套:
level=ERROR|该类型不需要初始化!
计算前初始化=[{"key":"轮滑社","title":"您最喜欢的社团","value":0},{"key":"篮球协会","title":"您最喜欢的社团","value":0},{"key":"羽毛球社","title":"您最喜欢的社团","value":0},{"key":"辩论社","title":"您最喜欢的社团","value":0},{"key":"m","title":"长度的单位","value":0},{"key":"km","title":"长度的单位","value":0},{"key":"kg","title":"长度的单位","value":0},{"key":"cm","title":"长度的单位","value":0},{"key":"℃","title":"长度的单位","value":0},{"key":"㎡","title":"长度的单位","value":0}]
level=INFO|selected=============[2]
level=INFO|selected=============[1, 2, 3]
level=INFO|selected=============[0]
level=INFO|selected=============[0, 1, 3]
level=INFO|selected=============[1]
level=INFO|selected=============[0, 2, 3]
计算后结果=[{"key":"轮滑社","title":"您最喜欢的社团","value":1},{"key":"篮球协会","title":"您最喜欢的社团","value":1},{"key":"羽毛球社","title":"您最喜欢的社团","value":1},{"key":"辩论社","title":"您最喜欢的社团","value":0},{"key":"m","title":"长度的单位","value":2},{"key":"km","title":"长度的单位","value":2},{"key":"kg","title":"长度的单位","value":2},{"key":"cm","title":"长度的单位","value":3},{"key":"℃","title":"长度的单位","value":0},{"key":"㎡","title":"长度的单位","value":0}]
现在,我们更换Jdk,采用流的方式进行统计计算:
public class AnswerContentVo {
private String title;
private Integer type;
private String selects;
private String selected;
private String dataAnalyzes;
//getter和setter方法略
}
@RequestMapping("/*****")
String questionStastic(@RequestBody String reqStr, HttpServletRequest request){
QueAnswer reqVo = new InfoReqUtil().returnBean("查看用户是否已经答题", reqStr, QueAnswer.class);
List<QueAnswer> resultAnswer=queAnswerService.select(reqVo);
if(resultAnswer==null || resultAnswer.size() == 0){
return ResponseWrap.failure("暂时没有问卷答案信息");
}else{
List<List<AnswerContentVo>> ansList = resultAnswer.parallelStream()
.map(it -> JSONArray.parseArray(it.getAnswerContent(), AnswerContentVo.class))
.collect(Collectors.toList());
List<AnswerContentVo> answerContentVos = ansList.get(0);
// 分析数据
answerContentVos.parallelStream().filter(o -> o.getType() != 2).forEach(o -> {
// 已选
List<Integer> selected = JSONArray.parseArray(o.getSelected(), Integer.class);
// 选项
JSONArray ans = JSONArray.parseArray(o.getSelects());
Map<Integer, Integer> dataAnalyzes = new HashMap<>(ans.size());
for (int i = 0; i < ans.size(); i++) {
dataAnalyzes.put(i, selected.contains(i) ? 1 : 0);
}
o.setDataAnalyzes(JSON.toJSONString(dataAnalyzes));
});
if (ansList.size() > 1) {
int len = answerContentVos.size();
IntStream.range(1, ansList.size())
.boxed() // 不可使用并发流
.forEach(o -> IntStream.range(0, len)
.boxed()
.parallel()
.filter(e -> answerContentVos.get(e).getType() != 2)
.forEach(e -> {
String datas = answerContentVos.get(e).getDataAnalyzes();
Map<Integer, Integer> dataAnalyzes = (Map<Integer, Integer>)JSON.parseObject(datas, Map.class);
List<Integer> selectedB = JSONArray.parseArray(ansList.get(o).get(e).getSelected(), Integer.class);
for (Integer s :
selectedB) {
dataAnalyzes.put(s, dataAnalyzes.get(s) + 1);
}
answerContentVos.get(e).setDataAnalyzes(JSON.toJSONString(dataAnalyzes));
}));
}
return ResponseWrap.success(JSON.toJSONString(answerContentVos));
}
}