| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.Text; |
| using OfficeOpenXml.FormulaParsing.ExpressionGraph; |
| |
| namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math |
| { |
| public class Rank : ExcelFunction |
| { |
| bool _isAvg; |
| public Rank(bool isAvg=false) |
| { |
| _isAvg=isAvg; |
| } |
| public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) |
| { |
| ValidateArguments(arguments, 2); |
| var number = ArgToDecimal(arguments, 0); |
| var refer = arguments.ElementAt(1); |
| bool asc = false; |
| if (arguments.Count() > 2) |
| { |
| asc = base.ArgToBool(arguments, 2); |
| } |
| var l = new List<double>(); |
| |
| foreach (var c in refer.ValueAsRangeInfo) |
| { |
| var v = Utils.ConvertUtil.GetValueDouble(c.Value, false, true); |
| if (!double.IsNaN(v)) |
| { |
| l.Add(v); |
| } |
| } |
| l.Sort(); |
| double ix; |
| if (asc) |
| { |
| ix = l.IndexOf(number)+1; |
| if(_isAvg) |
| { |
| int st = Convert.ToInt32(ix); |
| while (l.Count > st && l[st] == number) st++; |
| if (st > ix) ix = ix + ((st - ix) / 2D); |
| } |
| } |
| else |
| { |
| ix = l.LastIndexOf(number); |
| if (_isAvg) |
| { |
| int st = Convert.ToInt32(ix)-1; |
| while (0 <= st && l[st] == number) st--; |
| if (st+1 < ix) ix = ix - ((ix - st - 1) / 2D); |
| } |
| ix = l.Count - ix; |
| } |
| if (ix <= 0 || ix>l.Count) |
| { |
| return new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); |
| } |
| else |
| { |
| return CreateResult(ix, DataType.Decimal); |
| } |
| } |
| } |
| } |