zoukankan      html  css  js  c++  java
  • 算法--区间数据计算

    最近一年多来,一直比较忙,最近一段时间终于空闲了,把以前没写的都补上.....

    这边随笔主要是计算一系列数据的间隔数据。从一堆数据中查询出每个区间的起始数据,结束数据以及数据个数,同时可以设置相应精度(小数位数)。

    区间数据数据结构

     1、区间数据主要包括当前区间的起始数据,结束数据以及数据个数。结构如下:

        public struct IntervalData<TKey, TValue>
        {
            private TKey _startValue;
            private TKey _endValue;
            private TValue _count;
    
            public IntervalData(TKey startValue, TKey endValue, TValue count)
            {
                this._startValue = startValue;
                this._endValue = endValue;
                this._count = count;
            }
    
            public TKey StartValue
            {
                get { return this._startValue; }
                set { this._startValue = value; }
            }
    
            public TKey EndValue
            {
                get { return this._endValue; }
                set { this._endValue = value; }
            }
    
            public TValue Count
            {
                get { return this._count; }
                set { this._count = value; }
            }
        }
    

    区间数据计算算法

     首先需要注意的几点如下:

    1、区间应该大于等于1,精度必须小于等于15(double精度最大值)。

    2、区间宽度需要微调,相应需要增加相对应的精度值。

    3、最大值和最小值需要微调,相应需要增加或者减少相对应的精度值。

        public class DataCalculator
        {
            public int IntervalCount { get; set; }
    
            public double IntervalWidth { get; private set; }
    
            public double MaxValue { get; set; }
    
            public double MinValue { get; private set; }
    
            public const int MAX_DIGIT_SCALE = 15;
    
            public DataCalculator()
            {
    
            }
    
            public DataCalculator(int intervalCount)
            {
                if (intervalCount <= 0)
                {
                    this.IntervalCount = 1;
                }
                else
                {
                    this.IntervalCount = intervalCount;
                }
            }
    
            /// <summary>
            /// 计算间隔数据起始点,结束点以及数量的列表。
            /// </summary>
            /// <param name="values">需要计算的数值列表。</param>
            /// <param name="digits">小数点位数。用于精确到指定位数的小数点。
            /// 大于等于0,小于等于15。小于0时设置为0,大于15时设置为15。</param>
            /// <returns>返回间隔数据列表。</returns>
            public IList<IntervalData<double, int>> Calculate(IList<double> values, int digits = 0)
            {
                if (values == null || values.Count == 0)
                {
                    return new List<IntervalData<double, int>>();
                }
    
                CheckDoubleScale(ref digits);
                AdjustMinAndMaxValue(values, digits);
                AdjustIntervalWidth(digits);
    
                return CalculateResult(values, digits);
            }
    
            private IList<IntervalData<double, int>> CalculateResult(IEnumerable<double> values, int digits)
            {
                var dataResult = new List<IntervalData<double, int>>();
                double startValue = this.MinValue;
    
                for (int index = 0; index < this.IntervalCount; index++)
                {
                    int count = 0;
                    double endValue = Math.Round(startValue + this.IntervalWidth, digits);
    
                    foreach (double currValue in values)
                    {
                        if (currValue >= startValue &&
                            currValue < endValue)
                        {
                            ++count;
                        }
                    }
    
                    if (index == this.IntervalCount - 1 && this.MaxValue < endValue)
                    {
                        this.MaxValue = endValue;
                    }
    
                    dataResult.Add(new IntervalData<double, int>(startValue, endValue, count));
                    startValue = endValue;
                }
    
                return dataResult;
            }
    
            private void AdjustIntervalWidth(int digits)
            {
                double intervalWidth = (this.MaxValue - this.MinValue) / this.IntervalCount;
                double currentIntervalWidth = Math.Round(intervalWidth, digits);
    
                if (currentIntervalWidth < intervalWidth)
                {
                    currentIntervalWidth += 1 / Math.Pow(10, digits);
                }
    
                if (currentIntervalWidth == 0)
                {
                    currentIntervalWidth = 1;
                }
    
                this.IntervalWidth = currentIntervalWidth;
            }
    
            private void AdjustMinAndMaxValue(IEnumerable<double> values, int digits)
            {
                double minValue = values.Min();
                double maxValue = values.Max();
    
                // 计算最小值,将最小值减少相应的精度值,避免最小值未进入计算
                double currentMinValue = Math.Round(minValue, digits);
    
                if (currentMinValue > minValue)
                {
                    currentMinValue -= 1 / Math.Pow(10, digits);
                }
    
                // 计算最大值,将最大值增加相应的精度值,避免最大值未进入计算
                double currentMaxValue = Math.Round(maxValue, digits);
    
                if (currentMaxValue <= maxValue)
                {
                    currentMaxValue += 1 / Math.Pow(10, digits);
                }
    
                this.MinValue = currentMinValue;
                this.MaxValue = currentMaxValue;
            }
    
            private static void CheckDoubleScale(ref int digits)
            {
                if (digits < 0)
                {
                    digits = 0;
                }
    
                if (digits > MAX_DIGIT_SCALE)
                {
                    digits = MAX_DIGIT_SCALE;
                }
            }
        }

    具体应用

    应用比较简单,示例如下:

                IList<double> dataPoints = new List<double>() { -4, 5, 6, 99.54, 0, 65 };
    
                var calculator = new DataCalculator(5);
                IList<IntervalData<double, int>> datas = calculator.Calculate(dataPoints, 2);
    
                StringBuilder builder = new StringBuilder();
    
                foreach (var data in datas)
                {
                    builder.AppendLine(string.Format("StartValue:{0}  EndValue:{1}  Count:{2}", data.StartValue, data.EndValue, data.Count));
                }
    
                string result = builder.ToString();
                Console.Write(result);

    输出结果为:

    StartValue:-4  EndValue:16.71  Count:4
    StartValue:16.71  EndValue:37.42  Count:0
    StartValue:37.42  EndValue:58.13  Count:0
    StartValue:58.13  EndValue:78.84  Count:1
    StartValue:78.84  EndValue:99.55  Count:1

    可以将该返回数据用于相关图形进行绑定以及显示。

  • 相关阅读:
    解决ie下vue列表数据不能即时刷新的问题
    redis的几个知识点
    oracle查找某个字符在字符串中的个数的技巧
    程序员必看书籍
    eclipse彻底去除validation(彻底解决编辑js文件的卡顿问题)
    eclipse强行停止buliding workspace
    [Ljava.lang.String是一个字符串数组的字节码表示
    javascript合并两个数组
    css隐藏页面元素的方法
    配置IIS使用Python
  • 原文地址:https://www.cnblogs.com/jasenkin/p/interval_data_calculator.html
Copyright © 2011-2022 走看看