• 区间数据计算


    区间数据计算

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

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

    区间数据数据结构

     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

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

    作者:JasenKin
    出处:http://www.cnblogs.com/jasenkin/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
    标签: C#Interval Data
  • 相关阅读:
    Linux 安装apache2时候遇到的问题
    ubuntu安装php时出现error: xml2config not found. Please check your libxml2 installation 的解决办法
    Linux一块网卡绑定2个IP地址
    php 满足条件后跳转的几种方法.
    Linux 安装php 遇到 libtool: link: `ext/date/php_date.lo' is not a valid libtool object
    js 光标移动到输入框最后位置函数
    Linux iptables 防火墙相关命令介绍及使用
    tcpdump的简单选项介绍
    子网掩码转换函数
    Linux 十六进制转换十进制的函数
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3188862.html
Copyright © 2020-2023  润新知