123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- namespace Masuit.Tools.Maths;
- /// <summary>
- /// 百分位元素选择器
- /// </summary>
- public static class PercentileSelector
- {
- private static T QuickSelect<T>(IList<T> arr, int left, int right, int k) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
- {
- while (true)
- {
- if (left == right)
- {
- return arr[left];
- }
- var pivotIndex = left + (right - left) / 2;
- pivotIndex = Partition(arr, left, right, pivotIndex);
- if (k == pivotIndex)
- {
- return arr[k];
- }
- if (k < pivotIndex)
- {
- right = pivotIndex - 1;
- continue;
- }
- left = pivotIndex + 1;
- }
- }
- private static int Partition<T>(IList<T> arr, int left, int right, int pivotIndex) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
- {
- var pivotValue = arr[pivotIndex];
- Swap(arr, pivotIndex, right);
- var storeIndex = left;
- for (int i = left; i < right; i++)
- {
- if (arr[i].CompareTo(pivotValue) == -1)
- {
- Swap(arr, i, storeIndex);
- storeIndex++;
- }
- }
- Swap(arr, storeIndex, right);
- return storeIndex;
- }
- private static void Swap<T>(IList<T> arr, int i, int j)
- {
- (arr[i], arr[j]) = (arr[j], arr[i]);
- }
- /// <summary>
- /// 查找第percentile百分位的元素
- /// </summary>
- /// <param name="arr"></param>
- /// <param name="percentile"></param>
- public static T Percentile<T>(this IList<T> arr, double percentile) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
- {
- if (arr.Count == 0)
- {
- return default;
- }
- var k = (int)Math.Ceiling(arr.Count * percentile * 0.01) - 1;
- return QuickSelect(arr, 0, arr.Count - 1, k);
- }
- /// <summary>
- /// 查找第percentile百分位的元素
- /// </summary>
- /// <param name="arr"></param>
- /// <param name="percentile"></param>
- public static T Percentile<T>(this IEnumerable<T> arr, double percentile) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
- {
- return Percentile(arr.ToList(), percentile);
- }
- }
|