Code/Functions/Statistical/MedianFunction.cs
using Expressive.Expressions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Expressive.Functions.Statistical
{
    internal class MedianFunction : FunctionBase
    {
        #region FunctionBase Members

        public override string Name => "Median";

        public override object Evaluate(IExpression[] parameters, Context context)
        {
            this.ValidateParameterCount(parameters, -1, 1);

            IList<decimal> decimalValues = new List<decimal>();

            foreach (var p in parameters)
            {
                var value = p.Evaluate(this.Variables);

                if (value is IEnumerable enumerable)
                {
                    foreach (var item in enumerable)
                    {
                        AddValue(item, decimalValues);
                    }
                }
                else
                {
                    AddValue(value, decimalValues);
                }
            }

            return Median(decimalValues.ToArray());
        }

        #endregion

        private static void AddValue(object value, IList<decimal> decimalValues)
        {
            if (value is null)
            {
                return;
            }

            decimalValues.Add(Convert.ToDecimal(value));
        }

        private static decimal Median(IEnumerable<decimal> xs)
        {
            var ys = xs.OrderBy(x => x).ToList();
            var mid = (ys.Count - 1) / 2.0;
            return (ys[(int)(mid)] + ys[(int)(mid + 0.5)]) / 2;
        }
    }
}