/// <summary>
        ///     解析因子在记录中的连续次数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="numbers">记录</param>
        /// <param name="factors"></param>
        /// <param name="predictiveFactor">反因子</param>
        /// <param name="numbersTailCutCount"></param>
        /// <param name="allowMinTimes">允许的最小连续数,大于等于此数才记录</param>
        /// <returns></returns>
        public static PermutationFactorTrendConsecutiveDetails <T> CountConsecutive <T>(IReadOnlyList <T> numbers, List <List <T> > factors, List <T> predictiveFactor, int numbersTailCutCount = 1, int allowMinTimes = 1)
        {
            var curResult = new PermutationFactorTrendConsecutiveDetails <T>
            {
                Factors                    = factors,
                PredictiveFactor           = predictiveFactor,
                HistoricalConsecutiveTimes = new SortedDictionary <int, int>()
            };
            var i = 0;

            //连续次数
            var times = 0;

            //统计记录的长度
            var length = numbers.Count - numbersTailCutCount;

            //遍历所有记录
            while (i < length)
            {
                /*
                 * 排列因子:{1,2}{3,4}
                 * 号码索引位置:1 2 3 4 5 6 7 8 9 10 11 12 13
                 * 号码:        6 1 3 5 2 3 2 4 1 0  0  1  1
                 *            0 1 2 0 1 2 1 2 1 0  0  1  1
                 * (1命中第一个因子,2命中第二个因子,只有同时命中1、2才能算一次,并且索引位置跳到下一位置,比如索引位置2,3,同时命中1,2,连续次数递增1)
                 *
                 */
                var n = 0;
                for (; n < factors.Count && n + i < length; n++)
                {
                    if (!factors[n].Exists(m => m.Equals(numbers[n + i])))
                    {
                        break;
                    }
                }

                //排列因子全部相等
                if (n >= factors.Count)
                {
                    //连续次数递增
                    times++;

                    //索引位置调整,指向下一索引位置的前一条记录
                    i = i + factors.Count - 1;
                }
                else
                {
                    //是否有相同的连续次数,有则递增,否则新增一条连续次数记录
                    if (curResult.HistoricalConsecutiveTimes.ContainsKey(times))
                    {
                        curResult.HistoricalConsecutiveTimes[times]++;
                    }
                    else if (times >= allowMinTimes)
                    {
                        curResult.HistoricalConsecutiveTimes.Add(times, 1);
                    }

                    //连续次数清零,下一次重新统计
                    times = 0;
                }
                i++;
            }

            //是否有相同的连续次数,有则递增,否则新增一条连续次数记录
            if (curResult.HistoricalConsecutiveTimes.ContainsKey(times))
            {
                curResult.HistoricalConsecutiveTimes[times]++;
            }
            else if (times >= allowMinTimes)
            {
                curResult.HistoricalConsecutiveTimes.Add(times, 1);
            }
            return(curResult);
        }
        /// <summary>
        ///     分析因子的历史正确率分布等,(通过号码集合分析历史趋势)
        /// </summary>
        /// <param name="numbers">号码集合</param>
        /// <param name="trendResult">统计结果</param>
        /// <param name="endIndex">分析记录的最后索引位置</param>
        /// <param name="predictiveFactor">可能的因子</param>
        /// <returns></returns>
        public List <FactorTrendCorrectRate> GetCorrectRates <T>(List <T> numbers, PermutationFactorTrendConsecutiveDetails <T> trendResult, int endIndex, List <T> predictiveFactor)
        {
            var trends = new List <FactorTrendCorrectRate>();

            if (endIndex <= 0)
            {
                throw new Exception("分析历史趋势时,分析记录数量不能小于等于0!");
            }

            if (numbers == null || numbers.Count == 0)
            {
                throw new Exception("分析历史趋势时,记录不能为空!");
            }

            var numberCount = numbers.Count;

            if (numberCount < endIndex)
            {
                throw new Exception("分析历史趋势时,分析记录数量不能大于记录数量!");
            }

            var minConsecutiveTimes = trendResult.FactorDistributions.Where(n => n.ConsecutiveTimes != 0).Min(n => n.ConsecutiveTimes);
            var maxConsecutiveTimes = trendResult.FactorDistributions.Where(n => n.ConsecutiveTimes != 0).Max(n => n.ConsecutiveTimes);

            var minInterval = trendResult.FactorDistributions.Where(n => n.MaxConsecutiveTimesInterval != DisConsecutiveFlag).Min(n => n.MaxConsecutiveTimesInterval);
            var maxInterval = trendResult.FactorDistributions.Where(n => n.MaxConsecutiveTimesInterval != DisConsecutiveFlag).Max(n => n.MaxConsecutiveTimesInterval);

            //允许的连续次数,由小到大
            for (var consecutiveTimes = minConsecutiveTimes; consecutiveTimes <= maxConsecutiveTimes; consecutiveTimes++)
            {
                //允许的间隔数,由大到小
                for (var interval = maxInterval; interval >= minInterval; interval--)
                {
                    var resultCount  = 0;
                    var successCount = 0;

                    var trend = new FactorTrendCorrectRate
                    {
                        AllowConsecutiveTimes = consecutiveTimes,
                        AllowInterval         = interval,
                        AnalyseNumberCount    = endIndex
                    };
                    trends.Add(trend);

                    //行明细结果集
                    var distributions = trendResult.FactorDistributions;
                    for (var i = numberCount - 1; i >= endIndex; i--)
                    {
                        var number = numbers[i];

                        //上一索引位置的分析结果,10个号码,分析第10位(索引位置9),取第9位(索引位置8)
                        var distribution = distributions.FirstOrDefault(d => d.Index == i - 1);// distributions[i - 1];
                        if (distribution == null)
                        {
                            continue;
                        }

                        //对结果再分析
                        //1、按允许的最小因子当前连续次数和允许的最大间隔次数筛选
                        //2、先按最大连续次数然后按最小间隔次数排序

                        ////历史最大连续次数
                        //var historicalMaxConsecutiveTimes = curIndexResult.ConsecutiveTimes + interval;
                        if (distribution.ConsecutiveTimes == consecutiveTimes && distribution.MaxConsecutiveTimesInterval == interval)
                        {
                            resultCount++;

                            if (predictiveFactor.Contains(number))
                            {
                                successCount++;
                            }
                        }
                    }

                    trend.AnalyticalCount = resultCount;
                    trend.CorrectCount    = successCount;
                    trend.CorrectRate     = trend.AnalyticalCount == 0 ? 0 : (double)trend.CorrectCount / trend.AnalyticalCount;
                }
            }
            return(trends);
        }