| using System; | 
| using System.Collections.Generic; | 
| using System.Text; | 
| using System.Linq; | 
|   | 
| namespace Jace.Util | 
| { | 
|     static class MathExtended | 
|     { | 
|         /// <summary> | 
|         /// Partitions the given list around a pivot element such that all elements on left of pivot are <= pivot | 
|         /// and the ones at thr right are > pivot. This method can be used for sorting, N-order statistics such as | 
|         /// as median finding algorithms. | 
|         /// Pivot is selected ranodmly if random number generator is supplied else its selected as last element in the list. | 
|         /// Reference: Introduction to Algorithms 3rd Edition, Corman et al, pp 171 | 
|         /// </summary> | 
|         private static int Partition<T>(this IList<T> list, int start, int end, Random rnd = null) where T : IComparable<T> | 
|         { | 
|             if (rnd != null) | 
|                 list.Swap(end, rnd.Next(start, end + 1)); | 
|   | 
|             var pivot = list[end]; | 
|             var lastLow = start - 1; | 
|             for (var i = start; i < end; i++) | 
|             { | 
|                 if (list[i].CompareTo(pivot) <= 0) | 
|                     list.Swap(i, ++lastLow); | 
|             } | 
|             list.Swap(end, ++lastLow); | 
|             return lastLow; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Returns Nth smallest element from the list. Here n starts from 0 so that n=0 returns minimum, n=1 returns 2nd smallest element etc. | 
|         /// Note: specified list would be mutated in the process. | 
|         /// Reference: Introduction to Algorithms 3rd Edition, Corman et al, pp 216 | 
|         /// </summary> | 
|         public static T NthOrderStatistic<T>(this IList<T> list, int n, Random rnd = null) where T : IComparable<T> | 
|         { | 
|             return NthOrderStatistic(list, n, 0, list.Count - 1, rnd); | 
|         } | 
|         private static T NthOrderStatistic<T>(this IList<T> list, int n, int start, int end, Random rnd) where T : IComparable<T> | 
|         { | 
|             while (true) | 
|             { | 
|                 var pivotIndex = list.Partition(start, end, rnd); | 
|                 if (pivotIndex == n) | 
|                     return list[pivotIndex]; | 
|   | 
|                 if (n < pivotIndex) | 
|                     end = pivotIndex - 1; | 
|                 else | 
|                     start = pivotIndex + 1; | 
|             } | 
|         } | 
|   | 
|         public static void Swap<T>(this IList<T> list, int i, int j) | 
|         { | 
|             if (i == j)   //This check is not required but Partition function may make many calls so its for perf reason | 
|                 return; | 
|             var temp = list[i]; | 
|             list[i] = list[j]; | 
|             list[j] = temp; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Note: specified list would be mutated in the process. | 
|         /// </summary> | 
|         public static T Median<T>(this IList<T> list) where T : IComparable<T> | 
|         { | 
|             return list.NthOrderStatistic((list.Count - 1) / 2); | 
|         } | 
|   | 
|         public static double Median<T>(this IEnumerable<T> sequence, Func<T, double> getValue) | 
|         { | 
|             var list = sequence.Select(getValue).ToList(); | 
|             var mid = (list.Count - 1) / 2; | 
|             return list.NthOrderStatistic(mid); | 
|         } | 
|     } | 
| } |