最近一年多來,一直比較忙,最近一段時間終於空閑了,把以前沒寫的都補上.....
這邊隨筆主要是計算一系列數據的間隔數據。從一堆數據中查詢出每個區間的起始數據,結束數據以及數據個數,同時可以設置相應精度(小數位數)。
區間數據數據結構
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
可以將該返回數據用於相關圖形進行綁定以及顯示。