Calculate Calculate Mean, Median, and Mode (average calculations) in C#.

``````// ============================================================================
// ============================================================================

//-----------------------------------------------------------------------
namespace MathsLibrary.Average
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Mean calcuation
/// </summary>
public class Mean
{
/// <summary>
/// Calculate the specified  meandata.
/// </summary>
/// <param name='data'>
/// Data to have the mean calculated
/// </param>
/// <returns>Mean value</returns>
public static decimal Calculate(List<decimal> data)
{
if (data == null)
{
throw new ArgumentNullException();
}

if (data.Count == 0)
{
throw new ArgumentException("No data provided");
}

return data.Sum() / data.Count;
}
}
}

//-----------------------------------------------------------------------
namespace MathsLibrary.Average
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Median calculator
/// </summary>
public class Median
{
/// <summary>
/// Calculate the specified data.
/// </summary>
/// <param name='data'>
/// Data to be averaged
/// </param>
/// <returns>Median data</returns>
public static decimal Calculate(List<decimal> data)
{
if (data == null)
{
throw new ArgumentNullException();
}

if (data.Count == 0)
{
throw new ArgumentException("No data provided");
}

data.Sort();

if (IsEven(data.Count))
{
return CalculatWithEvenData(data);
}
else
{
return CalculatWithOddData(data);
}
}

/// <summary>
/// Calculats the median the with odd data elements.
/// </summary>
/// <returns>
/// The with odd data.
/// </returns>
/// <param name='data'>
/// Data to be averaged
/// </param>
/// <returns>Median data</returns>
private static decimal CalculatWithOddData(List<decimal> data)
{
var middlePosition = (decimal)data.Count / 2;

--middlePosition;

return data[(int)Math.Ceiling((decimal)middlePosition)];
}

/// <summary>Calculats the with even data.</summary>
/// <returns>The with even data.</returns>
/// <param name='data'>Data to be averaged</param>
/// <returns>averaged data</returns>
private static decimal CalculatWithEvenData(List<decimal> data)
{
var middlePosition = data.Count / 2;

--middlePosition;

var lower = data[middlePosition];
var upper = data[middlePosition + 1];

return (lower + upper) / 2;
}

/// <summary>Is the int even</summary>
/// <returns>True/False is the count is event.</returns>
/// <param name='count'>Element being analysed</param>
private static bool IsEven(int count)
{
decimal divCheck = (decimal)count / 2;

return (divCheck - Math.Floor(divCheck)) == 0;
}
}
}

//-----------------------------------------------------------------------
namespace MathsLibrary.Average
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Mode Average
/// </summary>
public class Mode
{
/// <summary>
/// Calculate the mode average
/// </summary>
/// <param name='data'>
/// Data to be averages
/// </param>
/// <returns>Mode average</returns>
public static decimal Calculate(List<decimal> data)
{
if (data == null)
{
throw new ArgumentNullException();
}

if (data.Count == 0)
{
throw new ArgumentException("No data provided");
}

var occuranceCount = CountOccurances(data);
var maxOccurance = occuranceCount.Max(x => x.Value);
var valueWithMaxOccurance = occuranceCount.Where(x => x.Value == maxOccurance).Select(x => x.Key);

if (valueWithMaxOccurance.ToList().Count > 1)
{
throw new NotImplementedException("We have not quite got around to  Mode with grouping...");
}

return valueWithMaxOccurance.First();
}

/// <summary>
/// Counts the occurances.
/// </summary>
/// <returns>
/// Dictionary of element vs occurance count
/// </returns>
/// <param name='data'>
/// Data being analysed
/// </param>
/// <returns>Dictionary of occurances of elements</returns>
private static Dictionary<decimal, int> CountOccurances(List<decimal> data)
{
var counter = new Dictionary<decimal, int>();

foreach (decimal value in data)
{
if (counter.ContainsKey(value))
{
counter[value] += 1;
}
else
{
counter[value] = 1;
}
}

return counter;
}
}
}

// --------------------------------------------------------------------------
// Unit tests
// --------------------------------------------------------------------------

//-----------------------------------------------------------------------
namespace MathsLibrary.Tests
{
using System;
using System.Collections.Generic;
using MathsLibrary.Average;
using NUnit.Framework;

/// <summary>
/// Mean tests.
/// </summary>
[TestFixture]
public class MeanTests
{
/// <summary>
/// Mean test
/// </summary>
[Test]
public void CanCalculateMean()
{
var data = new List<decimal> { 1.1m, 2.2m, 3.3m, 4.4m, 5.5m };

var modeValue = Mean.Calculate(data);

Assert.AreEqual(modeValue, 3.3);
}

/// <summary>
/// Checks error thrown when null passed in
/// </summary>
[Test]
public void WillThrowArgumentNullExceptionWhenNull()
{
Assert.Throws<ArgumentNullException>(() => Mean.Calculate(null));
}

/// <summary>
/// Checks error thrown when an empty collection is passed in.
/// </summary>
[Test]
public void WillThrowArgumentExceptionWhenEmptyCollection()
{
Assert.Throws<ArgumentException>(() => Mean.Calculate(new List<decimal>()));
}
}
}

//-----------------------------------------------------------------------
namespace MathsLibrary.Tests
{
using System;
using System.Collections.Generic;
using MathsLibrary.Average;
using NUnit.Framework;

/// <summary>
/// Median tests.
/// </summary>
[TestFixture]
public class MedianTests
{
/// <summary>
/// Determines whether this instance can calculate median with odd number.
/// </summary>
[Test]
public void CanCalculateMedianWithOddNumber()
{
var data = new List<decimal> { 1.1m, 2.2m, 3.3m, 4.4m, 5.5m };

var medianVale = Median.Calculate(data);

Assert.AreEqual(medianVale, 3.3);
}

/// <summary>
/// Determines whether this instance can calculate median with even number.
/// </summary>
[Test]
public void CanCalculateMedianWithEvenNumber()
{
var data = new List<decimal> { 1.1m, 2.2m, 3.3m, 4.4m };

var medianVale = Median.Calculate(data);

Assert.AreEqual(medianVale, 2.75);
}

/// <summary>
/// Wills the throw argument null exception when null.
/// </summary>
[Test]
public void WillThrowArgumentNullExceptionWhenNull()
{
Assert.Throws<ArgumentNullException>(() => Median.Calculate(null));
}

/// <summary>
/// Wills the throw argument exception when empty collection.
/// </summary>
[Test]
public void WillThrowArgumentExceptionWhenEmptyCollection()
{
Assert.Throws<ArgumentException>(() => Median.Calculate(new List<decimal>()));
}
}
}

//-----------------------------------------------------------------------

namespace MathsLibrary.Tests
{
using System;
using System.Collections.Generic;
using MathsLibrary.Average;
using NUnit.Framework;

/// <summary>
/// Mode tests.
/// </summary>
[TestFixture]
public class ModeTests
{
/// <summary>
/// Determines whether this instance can calculate mode with no grouping.
/// </summary>
[Test]
public void CanCalculateModeWithNoGrouping()
{
var data = new List<decimal> { 1.1m, 2.2m, 2.2m, 3.3m, 4.4m, 5.5m };

var modeValue = Mode.Calculate(data);

Assert.AreEqual(modeValue, 2.2);
}

/// <summary>
/// Determines whether this instance can not calculate modewith grouping.
/// </summary>
[Test]
public void CanNotCalculateModewithGrouping()
{
var data = new List<decimal> { 1.1m, 2.2m };

Assert.Throws<NotImplementedException>(() => Mode.Calculate(data));
}

/// <summary>
/// Wills the throw argument null exception when null.
/// </summary>
[Test]
public void WillThrowArgumentNullExceptionWhenNull()
{
Assert.Throws<ArgumentNullException>(() => Mode.Calculate(null));
}

/// <summary>
/// Wills the throw argument exception when empty collection.
/// </summary>
[Test]
public void WillThrowArgumentExceptionWhenEmptyCollection()
{
Assert.Throws<ArgumentException>(() => Mode.Calculate(new List<decimal>()));
}
}
}``````