Skip to content
This repository was archived by the owner on Nov 14, 2022. It is now read-only.

Commit c1ac68f

Browse files
Added support for MEDIAN function
2 parents 6d867d9 + 1474cdc commit c1ac68f

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

ClosedXML/Excel/CalcEngine/Functions/Statistical.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static void Register(CalcEngine ce)
5252
//LOGNORMDIST Returns the cumulative lognormal distribution
5353
ce.RegisterFunction("MAX", 1, int.MaxValue, Max);
5454
ce.RegisterFunction("MAXA", 1, int.MaxValue, MaxA);
55-
//MEDIAN Returns the median of the given numbers
55+
ce.RegisterFunction("MEDIAN", 1, int.MaxValue, Median);
5656
ce.RegisterFunction("MIN", 1, int.MaxValue, Min);
5757
ce.RegisterFunction("MINA", 1, int.MaxValue, MinA);
5858
//MODE Returns the most common value in a data set
@@ -217,6 +217,11 @@ private static object MaxA(List<Expression> p)
217217
return GetTally(p, false).Max();
218218
}
219219

220+
private static object Median(List<Expression> p)
221+
{
222+
return GetTally(p, false).Median();
223+
}
224+
220225
private static object Min(List<Expression> p)
221226
{
222227
return GetTally(p, true).Min();

ClosedXML/Excel/CalcEngine/Functions/Tally.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,30 @@ public void AddValue(Object v)
6868
_numericValues = null;
6969
}
7070

71+
public double Median()
72+
{
73+
var nums = NumericValuesInternal()
74+
.OrderBy(n => n)
75+
.ToArray();
76+
77+
if (nums.Length == 0) throw new ApplicationException("No values");
78+
79+
var hasEvenCount = nums.Length % 2 == 0;
80+
81+
if (hasEvenCount)
82+
{
83+
var numElementsToSkip = (nums.Length / 2) - 1;
84+
85+
return nums.Skip(numElementsToSkip)
86+
.Take(2)
87+
.Average();
88+
}
89+
90+
var medianIndex = (nums.Length - 1) / 2;
91+
92+
return nums[medianIndex];
93+
}
94+
7195
public double Count()
7296
{
7397
return Count(NumbersOnly);

ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,65 @@ public void Max()
260260
Assert.AreEqual(96, value);
261261
}
262262

263+
[Test]
264+
public void Median_CellRangeOfNonNumericValues_ThrowsApplicationException()
265+
{
266+
//Arrange
267+
var ws = workbook.Worksheets.First();
268+
269+
//Act - Assert
270+
Assert.Throws<ApplicationException>(() =>
271+
{
272+
ws.Evaluate("AVERAGE(D3:D45)");
273+
});
274+
}
275+
276+
[Test]
277+
public void Median_EvenCountOfCellRange_ReturnsAverageOfTwoElementsInMiddleOfSortedList()
278+
{
279+
//Arrange
280+
var ws = workbook.Worksheets.First();
281+
282+
//Act
283+
double value = ws.Evaluate("MEDIAN(I3:I10)").CastTo<double>();
284+
285+
//Assert
286+
Assert.AreEqual(244.225, value, tolerance);
287+
}
288+
289+
[Test]
290+
public void Median_EvenCountOfManualNumbers_ReturnsAverageOfTwoElementsInMiddleOfSortedList()
291+
{
292+
//Act
293+
double value = workbook.Evaluate("MEDIAN(-27.5,93.93,64.51,-70.56)").CastTo<double>();
294+
295+
//Assert
296+
Assert.AreEqual(18.505, value, tolerance);
297+
}
298+
299+
[Test]
300+
public void Median_OddCountOfCellRange_ReturnsElementInMiddleOfSortedList()
301+
{
302+
//Arrange
303+
var ws = workbook.Worksheets.First();
304+
305+
//Act
306+
double value = ws.Evaluate("MEDIAN(I3:I11)").CastTo<double>();
307+
308+
//Assert
309+
Assert.AreEqual(189.05, value, tolerance);
310+
}
311+
312+
[Test]
313+
public void Median_OddCountOfManualNumbers_ReturnsElementInMiddleOfSortedList()
314+
{
315+
//Act
316+
double value = workbook.Evaluate("MEDIAN(-27.5,93.93,64.51,-70.56,101.65)").CastTo<double>();
317+
318+
//Assert
319+
Assert.AreEqual(64.51, value, tolerance);
320+
}
321+
263322
[Test]
264323
public void Min()
265324
{
@@ -391,7 +450,6 @@ public void VarP()
391450
value = workbook.Evaluate(@"=VARP(Data!H:H)").CastTo<double>();
392451
Assert.AreEqual(2189.430863, value, tolerance);
393452
}
394-
395453
private XLWorkbook SetupWorkbook()
396454
{
397455
var wb = new XLWorkbook();

0 commit comments

Comments
 (0)