我正在使用Apache POI 3.9,需要使用Excel公式PERCENTILE并从Java内评估该公式。

问题是不支持PERCENTILE。

我收到一个org.apache.poi.ss.formula.eval.NotImplementedException:错误

我有3种可能的解决方案来解决我的问题。


用Java编写我自己的percentile函数,并将其贡献给Apache POI库(请参见http://poi.apache.org/spreadsheet/eval-devguide.html
将Excel工作表中的相关单元格放入Java中,并使用诸如Percentile calculation中的函数进行计算
将PERCENTILE转换为SMALL函数
例如代替=PERCENTILE(A1:A10,95%)
然后=(SMALL(A1:A10,9)+SMALL(A1:A10,10))/2


此时,我需要一个快速的解决方案。对我来说,第三个是最好的,但结果却不尽相同。

在我退回到选项2(有点混乱)之前,是否有人有任何想法?

最佳答案

感谢Gagravarr的鼓励,也感谢您的Apache POI - How to register a function帖子,该帖子非常有帮助

我通过以下方式在库中实现了PERCENTILE函数:


我下载了Apache POI 3.9的源代码
我在src / resources / main / org / apache / poi / ss / formula / function / functionMetadata.txt(or online)中检查了PERCENTILE函数的ID号,它是328
因此我加了
retval[328] = AggregateFunction.PERCENTILE;
到文件org.apache.poi.ss.formula.eval.FunctionEval.java
我加了
public static final Function PERCENTILE = new Percentile();放在适当位置的文件org.apache.poi.ss.formula.functions.AggregateFunction.java中。
我在同一文件中添加了以下代码(我基于LargeSmall函数;我一直在寻找与我想做的最相似的现有代码/函数类型)

private static final class Percentile extends Fixed2ArgFunction {

protected Percentile() {
}

public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
        ValueEval arg1) {
    double dn;
    try {
        ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
        dn = OperandResolver.coerceValueToDouble(ve1);
    } catch (EvaluationException e1) {
        // all errors in the second arg translate to #VALUE!
        return ErrorEval.VALUE_INVALID;
    }
    if (dn < 0 || dn > 1) { // has to be percentage
        return ErrorEval.NUM_ERROR;
    }

    double result;
    try {
        double[] ds = ValueCollector.collectValues(arg0);
        int N = ds.length;
        double n = (N - 1) * dn + 1;
        if (n == 1d) {
            result = StatsLib.kthSmallest(ds, 1);
        } else if (n == N) {
            result = StatsLib.kthLargest(ds, 1);
        } else {
            int k = (int) n;
            double d = n - k;
            result = StatsLib.kthSmallest(ds, k) + d
                    * (StatsLib.kthSmallest(ds, k + 1) - StatsLib.kthSmallest(ds, k));
        }

        NumericFunction.checkValue(result);
    } catch (EvaluationException e) {
        return e.getErrorEval();
    }

    return new NumberEval(result);
}


}
然后,我分别上载了这两个文件,然后可以正常使用PERCENTILE函数。

09-27 21:08