Search code examples
c#.netepplusepplus-4

Sum n largest numbers EPPlus


I'm trying to sum the n largest numbers of a range.

My formula is: SUM(LARGE(A10:A15, {1,2}))

But I'm getting a #VALUE as result.

If I debug the formula execution to a log file I got that:

Worksheet: Sheet 1
Address: A9
OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException: #VALUE!
   em OfficeOpenXml.FormulaParsing.Excel.Functions.IntArgumentParser.Parse(Object obj)
   em OfficeOpenXml.FormulaParsing.Excel.Functions.ExcelFunction.ArgToInt(IEnumerable`1 arguments, Int32 index)
   em OfficeOpenXml.FormulaParsing.Excel.Functions.Math.Large.Execute(IEnumerable`1 arguments, ParsingContext context)
   em OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers.DefaultCompiler.Compile(IEnumerable`1 children, ParsingContext context)
   em OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionExpression.Compile()

Looks like the Large Function doesn't accept an array as a second argument.

How can I get the sum of n largest values formula in EPPlus?


Solution

  • Looks like this kind of formula only works when save the excel to file. In my case I don't want a file, just the calculated value.

    The solution was to extend de ExcelFunction class and create my own implementation:

    public class SumLargest: ExcelFunction
    {
    
        public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context)
        {
            ValidateArguments(arguments, 2);
    
            //n largest values
            var n = ArgToInt(arguments, 1);
    
            var cells = ArgsToDoubleEnumerable(arguments, context);
    
            var values = cells.ToList();
            values.RemoveAt(values.Count() - 1);
    
            var result = values
                .OrderByDescending(x => x)              
                .Take(n)
                .Sum();
    
            return CreateResult(result, DataType.Decimal);
        }
    
    }
    

    Then I added it to my package:

    using (ExcelPackage excelPackage = new ExcelPackage())
    {
         excelPackage.Workbook.FormulaParserManager.AddOrReplaceFunction("SUMLARGEST", new SumLargest());
         ....
    }
    

    And I can use it in a much better way then the original formula:

    Cells["C5"].Formula = "SUMLARGEST(A10:A15, 2)"
    

    Reference: https://github.com/JanKallman/EPPlus/wiki/Implementing-missing-or-new-Excel-functions