# java 彩票走势图算法

[这是XX网双色球的彩票走势图，博主这里是将彩票数据分区展示，以双色球为例，分了五个区域，本博文中的遗漏值是按照期数的降序排列计算的如下图]

彩票走势图的工具类**LotteryTrend**中将彩票的名称彩票的id，及其对应的数字域数据域id，每个区域的起始数字，每个区域的长度等数据按照顺序一一对应定义。另一个工具类**MissValue**就是彩票遗漏值的工具类，里面是具体的**彩票遗漏值、出现总次数、平均遗漏值、最大遗漏值、最大连出值**的计算方法，博主将开奖位置的遗漏值置为0，返给前端的。下面是这几个名词的定义：
**彩票遗漏值**：自上期开出到本期间隔的期数。
**出现总次数**：当前选定的彩票期数区间内该球的出现总次数。
**平均遗漏值**：平均遗漏值计算公式：总期数除以出现的总次数，如果总次数为0，该值为0；如果除不尽将计算结果向下取整。
**最大遗漏值**：历史开奖以来该球连续不出现的最大值，即为距离上次出现的间隔数的最大值。
**最大连出值**：**博主写的是选定期数内连续出现的最大值，与右图不符合**.


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.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* 彩票走势图工具类
*
*/
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]);
}
}
}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]);
}
}
}
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++) {
}
}
}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++) {
}
}
}

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();
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");
}
}

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();

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()) ;
}

});

for(Entry<String,Integer> newEntry :result){
}
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;

/**
* 计算遗漏值的工具类
*
*/
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){
}
}
}

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++) {
}
}
return list;
}

/**
* 计算每列开奖的总次数（即：出现总次数）
*
* 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++;
}
}
}
return list;
}

/**
* 计算平均遗漏值
*
* 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){
}else{
}
}
return list;
}

/**
* 计算最大遗漏值
*
* 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];
}
}
return ll;
}

/**
* 计算最大连出值
*
* 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]);
}
}
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;
}
}


**

**