一、算法介绍 本博文主要写了彩票走势图中的遗漏值、出现总次数、平均遗漏值、最大遗漏值、最大连出值的计算逻辑。
二、图文简介 [这是XX网双色球的彩票走势图,博主这里是将彩票数据分区展示,以双色球为例,分了五个区域,本博文中的遗漏值是按照期数的降序排列计算的如下图]
三、工具类简介(请仔细看完工具类简介)
彩票走势图的工具类**LotteryTrend**中将彩票的名称彩票的id,及其对应的数字域数据域id,每个区域的起始数字,每个区域的长度等数据按照顺序一一对应定义。
另一个工具类**MissValue**就是彩票遗漏值的工具类,里面是具体的**彩票遗漏值、出现总次数、平均遗漏值、最大遗漏值、最大连出值**的计算方法,博主将开奖位置的遗漏值置为0,返给前端的。下面是这几个名词的定义:
**彩票遗漏值**:自上期开出到本期间隔的期数。
**出现总次数**:当前选定的彩票期数区间内该球的出现总次数。
**平均遗漏值**:平均遗漏值计算公式:总期数除以出现的总次数,如果总次数为0,该值为0;如果除不尽将计算结果向下取整。
**最大遗漏值**:历史开奖以来该球连续不出现的最大值,即为距离上次出现的间隔数的最大值。
**最大连出值**:**博主写的是选定期数内连续出现的最大值,与右图不符合**.
四、返回给前端的json数据
五、代码块
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/** * 彩票走势图工具类
* @author Administrator * */
public class LotteryTrend {
//所有彩票名称数组
public static final String[] titleArray = {"超级大乐透", "七星彩", "排列三", "排列五", "双色球", "福彩3D", "江西11选5", "11运夺金", "广东11选5", "上海11选5", "浙江11选5", "七乐彩", "重庆时时彩", "胜负彩", "安徽快三", "湖北快三", "吉林快三", "江苏快三", "江苏11选5", "浙江12选5"};
//彩票的id数组
public static final String[] lotteryidArray = {"19", "18", "2", "13", "16", "1", "9", "8", "10", "24", "27", "17", "3", "71", "32", "33", "34", "35", "28", "22"};
//每种彩票的区域或者数字域
public static final String[][] headArray = {{"红一区", "红二区", "红三区", "后区"}, {"第七位", "第六位", "第五位", "第四位", "第三位", "第二位", "第一位"}, {"百位", "十位", "个位"},
{"万位", "千位", "百位", "十位", "个位"}, {"红一区", "红二区", "红三区", "篮球"}, {"百位", "十位", "个位"},
{"万位", "千位", "百位", "十位", "个位"}, {"万位", "千位", "百位", "十位", "个位"}, {"万位", "千位", "百位", "十位", "个位"},
{"万位", "千位", "百位", "十位", "个位"}, {"万位", "千位", "百位", "十位", "个位"}, {"一区", "二区", "三区"},
{"万位", "千位", "百位", "十位", "个位"}, {"3", "1", "0"}, {"百位", "十位", "个位"},
{"百位", "十位", "个位"}, {"百位", "十位", "个位"}, {"百位", "十位", "个位"},
{"万位", "千位", "百位", "十位", "个位"}, {"万位", "千位", "百位", "十位", "个位"}};
//区域或者数字域的id
public static final String[][] idxArray = {{"area1", "area2", "area3", "back"}, {"num_info7", "num_info6", "num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"num_info3", "num_info2", "num_info1"},
{"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"area1", "area2", "area3", "num_info7"}, {"num_info3", "num_info2", "num_info1"},
{"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"num_info5",
"num_info4", "num_info3", "num_info2", "num_info1"}, {"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"},
{"area1", "area2", "area3"}, {"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}, {"3", "1", "0"}, {"num_info3", "num_info2", "num_info1"},
{"num_info3", "num_info2", "num_info1"}, {"num_info3", "num_info2", "num_info1"}, {"num_info3", "num_info2", "num_info1"}, {"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"},
{"num_info5", "num_info4", "num_info3", "num_info2", "num_info1"}};
//定义每个区域的起始数字
public static final String[][] beginNum = {{"01", "13", "25", "01"}, {"0", "0", "0", "0", "0", "0", "0"}, {"0", "0", "0"},
{"0", "0", "0", "0", "0"}, {"01", "12", "23", "01"}, {"0", "0", "0"},
{"1", "1", "1", "1", "1"}, {"1", "1", "1", "1", "1"}, {"1", "1", "1", "1", "1"}, {"1", "1", "1", "1", "1"},
{"1", "1", "1", "1", "1"}, {"01", "11", "21"}, {"0", "0", "0", "0", "0"}, {"1", "1", "1"}, {"1", "1", "1"},
{"1", "1", "1"}, {"1", "1", "1"}, {"1", "1", "1"}, {"1", "1", "1", "1", "1"}, {"1", "1", "1", "1", "1"}};
//定义每个区域的长度
public static final int[][] horizontalSpans = {{12, 12, 11, 12}, {10, 10, 10, 10, 10, 10, 10}, {10, 10, 10},
{10, 10, 10, 10, 10}, {11, 11, 11, 16}, {10, 10, 10},
{11, 11, 11, 11, 11}, {11, 11, 11, 11, 11}, {11, 11, 11, 11, 11}, {11, 11, 11, 11, 11},
{11, 11, 11, 11, 11}, {10, 10, 10}, {10, 10, 10}, {14, 14, 14}, {6, 6, 6},
{6, 6, 6}, {6, 6, 6}, {6, 6, 6}, {11, 11, 11, 11, 11}, {12, 12, 12, 12, 12}};
//是否需要两位,例如01或者1
public static final String[] isHaveTwoPosition = {"1", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0"};
//冷热
public static final String[][] codeAndHotIdxArray = {{"num_info1", "num_info2", "num_info3", "num_info4", "num_info5", "num_info6", "num_info7"},
{"num_info1", "num_info2", "num_info3", "num_info4", "num_info5", "num_info6", "num_info7"}, {"num_info1", "num_info2", "num_info3"},
{"num_info3", "num_info2", "num_info1"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5", "num_info6", "num_info7"},
{"num_info3", "num_info2", "num_info1"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"},
{"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"},
{"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5", "num_info6", "num_info7"},
{"num_info3", "num_info2", "num_info1"}, {}, {"num_info1", "num_info2", "num_info3"}, {"num_info1", "num_info2", "num_info3"}, {"num_info1", "num_info2", "num_info3"},
{"num_info1", "num_info2", "num_info3"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"}, {"num_info1", "num_info2", "num_info3", "num_info4", "num_info5"}};
//封装走势图所有的数据
/**
* list 数据库查询到的当前彩种开奖数据集合
* issueCount 页面传来的指定的查看的总期数
* totalIssue 当前开奖数据历史以来的总期数
*/
public static Map<String, Object> trendInfo(List<Map<String, String>> list, String lotteryid, String idx, Integer issueCount, Integer totalIssue) {
int m = 0, n = 0, horizontalSpan = 0;//m代表当前彩种在彩票id数组的位置;n代表要展示的区域(如红一区,后区等)或者数字域(百位,十位,各位等);horizontalSpan水平方向的跨度
Map<String, Object> map = new LinkedHashMap<String, Object>();//封装返回数据的集合,包括alldiffs,average_omission,infolist,max_omission,max_output,placenum,result
//获取m
for (int i = 0; i < lotteryidArray.length; i++) {
if (lotteryidArray[i].equals(lotteryid)) {
m = i;
break;
}
}
//System.out.println("当前彩种在彩票id数组的位置:"+m);
//获取n
for (int i = 0; i < idxArray[m].length; i++) {
if (idxArray[i].equals(idx)) {
n = i;
break;
}
}
//System.out.println("要展示走势的当前彩票的区域:"+n);
//获取水平跨度
horizontalSpan = horizontalSpans[m][n];
//封装开奖数据
List<Map<String, String>> infolist = new ArrayList<>();
if (issueCount <= totalIssue) {
for (int j = 0; j < issueCount; j++) {
//封装每一条开奖数据
String[] sp = list.get(j).get("result").replaceFirst("\\+", ",").split(",");
Map<String, String> ma1 = new LinkedHashMap<String, String>();
//封装期号
ma1.put("id", list.get(j).get("id"));
//封装id
ma1.put("lottery_num", list.get(j).get("termNo"));
//封装开奖号码
for (int i = 0; i < codeAndHotIdxArray[m].length; i++) {
ma1.put(codeAndHotIdxArray[m][i], sp[i]);
}
infolist.add(ma1);
}
} else {
for (int j = 0; j < totalIssue; j++) {
//封装每一条开奖数据
String[] sp = list.get(j).get("result").replaceFirst("\\+", ",").split(",");
Map<String, String> ma1 = new LinkedHashMap<String, String>();
//封装期号
ma1.put("id", list.get(j).get("id"));
//封装id
ma1.put("lottery_num", list.get(j).get("termNo"));
//封装开奖号码
for (int i = 0; i < codeAndHotIdxArray[m].length; i++) {
ma1.put(codeAndHotIdxArray[m][i], sp[i]);
}
infolist.add(ma1);
}
}
map.put("infolist", infolist);
//转换数据格式
List<List<Integer>> convertList = MissingValue.convertAwardData(list);
//获得当前彩种的所有遗漏值数据
int[][] alldiff_totalIssue = MissingValue.getMissingvalue(convertList, Integer.parseInt(beginNum[m][n]), totalIssue, horizontalSpan);
//获得当前彩种的指定期的遗漏值数据
int[][] alldiffs = null;
if (issueCount <= totalIssue) {
alldiffs = new int[issueCount][horizontalSpan];
for (int i = 0; i < alldiffs.length; i++) {
for (int j = 0; j < horizontalSpan; j++) {
alldiffs[i][j] = alldiff_totalIssue[i][j];
}
}
} else {
alldiffs = new int[totalIssue][horizontalSpan];
for (int i = 0; i < alldiffs.length; i++) {
for (int j = 0; j < horizontalSpan; j++) {
alldiffs[i][j] = alldiff_totalIssue[i][j];
}
}
}
map.put("alldiffs", alldiffs);
//出现总次数
List<Integer> placenum = MissingValue.getTotal(alldiffs);
//平均遗漏值
List<Integer> average_omission = null;
if (issueCount <= totalIssue) {
average_omission = MissingValue.getCoverage(placenum, issueCount);
} else {
average_omission = MissingValue.getCoverage(placenum, totalIssue);
}
//最大遗漏值
List<Integer> max_omission = MissingValue.getMax(alldiff_totalIssue);
//最大连出值
List<Integer> max_output = MissingValue.getContinuous(alldiffs);
map.put("max_output", max_output);
map.put("placenum", placenum);
map.put("average_omission", average_omission);
map.put("max_omission", max_omission);
return map;
}
//封装冷热的数据
public static Map<String, Object> saveColoHot(List<Map<String, String>> list, String lotteryid, String idx, Integer issueCount, Integer totalIssue) {
int m = 0, n = 0;//m代表当前彩种在彩票id数组的位置,n代表冷热的区域
Map<String, Object> map = new LinkedHashMap<String, Object>();//封装返回数据的集合,包括alldiffs,average_omission,infolist,max_omission,max_output,placenum,result
//获取m
for (int i = 0; i < lotteryidArray.length; i++) {
if (lotteryidArray[i].equals(lotteryid)) {
m = i;
break;
}
}
//获取n
for (int i = 0; i < codeAndHotIdxArray[m].length; i++) {
if (codeAndHotIdxArray[i].equals(idx)) {
n = i;
break;
}
}
//获取开奖数据
List<List<String>> infolist = new ArrayList<>();
if (issueCount <= totalIssue) {
for (int j = 0; j < issueCount; j++) {
//封装每一条开奖数据
String[] sp = list.get(j).get("result").replaceFirst("\\+", ",").split(",");
List<String> li = new ArrayList<>();
//封装开奖号码
for (int i = 0; i < sp.length; i++) {
li.add(sp[i]);
}
infolist.add(li);
}
} else {
for (int j = 0; j < totalIssue; j++) {
//封装每一条开奖数据
String[] sp = list.get(j).get("result").replaceFirst("\\+", ",").split(",");
List<String> li = new ArrayList<>();
//封装开奖号码
for (int i = 0; i < sp.length; i++) {
li.add(sp[i]);
}
infolist.add(li);
}
}
List<LinkedHashMap<String, String>> placenum = getColdHot(infolist, idx, n);
map.put("placenum", placenum);
map.put("result", "success");
return map;
}
//获得冷热的数据
public static List<LinkedHashMap<String, String>> getColdHot(List<List<String>> infolist, String idx, Integer n) {
List<LinkedHashMap<String, String>> list = new ArrayList<>();
//对出现的次数做降序排列
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < infolist.size(); i++) {
if (map.containsKey(infolist.get(i).get(n))) {
map.put(infolist.get(i).get(n), map.get(infolist.get(i).get(n)) + 1);
} else {
map.put(infolist.get(i).get(n), 1);
}
}
List<Entry<String, Integer>> sortMap = sortMap(map);
//封装冷热图的数据
for (Entry<String, Integer> entry : sortMap) {
String key = entry.getKey();
Integer value = entry.getValue();
BigDecimal b1 = new BigDecimal(Double.toString(value * 100));
BigDecimal b2 = new BigDecimal(Double.toString(infolist.size()));
double countunm = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
LinkedHashMap<String, String> lhm = new LinkedHashMap<>();
lhm.put(idx, key);
lhm.put("countid", value + "");
String countunm1 = String.valueOf(countunm);
if ((countunm1.split("\\.")[1]).length() == 1) {//此情况代表countunm是整数,小数点后面只有一个0,为满足数据(数据格式:xx.yy00)封装要求,要添加三个0
lhm.put("countunm", countunm1 + "000");
} else {
lhm.put("countunm", countunm1 + "00");
}
list.add(lhm);
}
return list;
}
//对map集合value实现降序排列
public static List<Map.Entry<String, Integer>> sortMap(Map<String, Integer> map) {
//获取entrySet
Set<Map.Entry<String, Integer>> mapEntries = map.entrySet();
//使用链表来对集合进行排序,使用LinkedList,利于插入元素
List<Map.Entry<String, Integer>> result = new LinkedList<>(mapEntries);
//自定义比较器来比较链表中的元素
Collections.sort(result, new Comparator<Entry<String, Integer>>() {
//基于entry的值(Entry.getValue()),来排序链表
@Override
public int compare(Entry<String, Integer> o1,
Entry<String, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
//将排好序的存入到LinkedHashMap(可保持顺序)中,需要存储键和值信息对到新的映射中。
Map<String, Integer> linkMap = new LinkedHashMap<>();
for (Entry<String, Integer> newEntry : result) {
linkMap.put(newEntry.getKey(), newEntry.getValue());
}
/*//根据entrySet()方法遍历linkMap
for(Map.Entry<String, Integer> mapEntry : linkMap.entrySet()){
System.out.println("key:"+mapEntry.getKey()+" value:"+mapEntry.getValue());
}*/
return result;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @admistrator 计算遗漏值的工具类
*/
public class MissingValue {
/**
* 获取整个区域的遗漏值
* lis 开奖数据的集合(从数据查询到的开奖数据集合)
* row 行数
* column 列数
*/
public static int[][] getMissingvalue(List<List<Integer>> lis, Integer beginNum, Integer row, Integer horizontalSpan) {
int[][] arr = new int[row][horizontalSpan];
//获取整个区域的遗漏值
for (int k = 1; k <= horizontalSpan; k++) {
//获取每期开奖数据在当前列的位置
List<Integer> countList = new ArrayList<Integer>();
for (int i = 0; i <= lis.size() - 1; i++) {
for (int j = 0; j < lis.get(i).size(); j++) {
if (lis.get(i).get(j) > beginNum + horizontalSpan - 1) {
break;
}
if (lis.get(i).get(j) == k) {
countList.add(i);//记录当前列的开奖号码的行号
}
}
}
if (countList.size() != 0 && countList != null) {
int[] arrj = getOthers(countList, arr.length);
for (int j = 0; j < arrj.length; j++) {
arr[j][k - 1] = arrj[j];
}
} else {
for (int j = arr.length - 1; j >= 0; j--) {
arr[j][k - 1] = arr.length - j;
}
}
}
return arr;
}
//获取每列的遗漏值数据
public static int[] getOthers(List<Integer> list, int row) {
int[] array = new int[row];
int n = 0;
while (true) {
if (list.size() == 1) {
if (list.get(n) == 0) {//中奖号码只有一个且在顶部
array[n] = 0;
for (int i = array.length - 1; i > 0; i--) {
array[i] = array.length - i;
}
} else if (list.get(n) == row - 1) {//中奖号码只有一个且在底部
for (int i = list.get(n); i >= 0; i--) {
array[i] = list.get(n) - i;
}
} else if (list.get(n) > 0 && list.get(n) < row - 1) {//中奖号码只有一个且在中间
for (int i = array.length - 1; i > list.get(n); i--) {
array[i] = array.length - i;
}
for (int i = list.get(n); i >= 0; i--) {
array[i] = list.get(n) - i;
}
}
} else if (list.size() > 1) {
if (n == 0) {//第1个开奖号码
if (list.get(n) == 0) {//当前中奖号码在顶部
array[n] = 0;
} else if (list.get(n) < row - 1) {//当前号码在中间
for (int i = list.get(n); i >= 0; i--) {
array[i] = list.get(n) - i;
}
}
} else if (n + 1 < list.size() && n > 0) {//当前为第n+1个开奖号码,而且不是最后一个,那么当前号码一定在中间
if (list.get(n) - list.get(n - 1) - 1 != 0) {//开奖号码有间隔
for (int i = list.get(n); i > list.get(n - 1); i--) {
array[i] = list.get(n) - i;
}
} else {//开奖号码没有间隔
array[list.get(n)] = 0;
}
} else if (n + 1 == list.size() && n > 0) {//当前开奖号码为这一列的最后一个开奖号码
if (list.get(n) - list.get(n - 1) - 1 > 0) {//开奖号码有间隔
if (list.get(n) == row - 1) {//当前中奖号码在底部
for (int i = list.get(n); i > list.get(n - 1); i--) {
array[i] = list.get(n) - i;
}
} else if (list.get(n) < row - 1) {//当前号码在中间
for (int i = list.get(n); i > list.get(n - 1); i--) {
array[i] = list.get(n) - i;
}
for (int i = array.length - 1; i >= list.get(n) + 1; i--) {
array[i] = array.length - i;
}
}
} else if (list.get(n) - list.get(n - 1) - 1 == 0) {//开奖号码没有间隔
if (list.get(n) == row - 1) {//当前中奖号码在底部
array[list.get(n)] = 0;
} else if (list.get(n) < row - 1) {//当前号码在中间
array[list.get(n)] = 0;
for (int i = array.length - 1; i > list.get(n); i--) {
array[i] = array.length - i;
}
}
}
break;
}
}
if (n == list.size() - 1) {
break;
}
n++;
}
return array;
}
/**
* 处理开奖数据的方法
* 实现的功能:将每一期在当前区域的开奖数据获取出来,并转换为int 类型
* lis 开奖数据的集合
*/
public static List<List<Integer>> convertAwardData(List<Map<String, String>> lis) {
List<List<Integer>> list = new ArrayList<>();
for (int i = 0; i < lis.size(); i++) {
List<Integer> lii = new ArrayList<>();
String[] sp = lis.get(i).get("result").replaceFirst("\\+", ",").split(",");
for (int j = 0; j < sp.length; j++) {
lii.add(Integer.parseInt(sp[j]));
}
list.add(lii);
}
return list;
}
/**
* 计算每列开奖的总次数(即:出现总次数)
* <p>
* arr 遗漏值数据的数组
*/
public static List<Integer> getTotal(int[][] arr) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr[0].length; i++) {
int count = 0;
for (int j = 0; j < arr.length; j++) {
if (arr[j][i] == 0) {
count++;
}
}
list.add(count);
}
return list;
}
/**
* 计算平均遗漏值
* <p>
* lis 出现总次数集合
* row 总行数
*/
public static List<Integer> getCoverage(List<Integer> lis, Integer row) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < lis.size(); i++) {
if (lis.get(i) != 0) {
list.add(row / lis.get(i));
} else {
list.add(0);
}
}
return list;
}
/**
* 计算最大遗漏值
* <p>
* arr 遗漏值的集合
*/
public static List<Integer> getMax(int[][] arr) {
List<Integer> ll = new ArrayList<Integer>();
for (int i = 0; i < arr[0].length; i++) {
int max = arr[0][i];
for (int j = 0; j < arr.length; j++) {
if (arr[j][i] > max)
max = arr[j][i];
}
ll.add(max);
}
return ll;
}
/**
* 计算最大连出值
* <p>
* arr 遗漏值的集合
*/
public static List<Integer> getContinuous(int[][] arr) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr[0].length; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < arr.length; j++) {
sb.append(arr[j][i]);
}
list.add(max(sb.toString()));
}
return list;
}
//统计相同字符连续出现的最大子序列的长度
public static int max(String s) {
int max = 0, tmp_m = 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == s.charAt(i - 1)) {
tmp_m++;
} else {
max = max > tmp_m ? max : tmp_m;
tmp_m = 1;
}
}
max = max > tmp_m ? max : tmp_m;//最后的连续数与最大连续的比较
return max;
}
}