在Apache POI中使用Excel PERCENTILE函数

时间:2013-10-23 14:19:11

标签: java excel apache-poi

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

问题是不支持PERCENTILE。

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

我有3个可能解决问题的方法。

  1. 在java中编写我自己的百分位函数并将其贡献给Apache POI库(参见http://poi.apache.org/spreadsheet/eval-devguide.html

  2. 将Excel工作表中的相关单元格转换为java并使用Percentile calculation

  3. 中的函数计算它们
  4. 将PERCENTILE转换为SMALL函数 比如=PERCENTILE(A1:A10,95%)而不是=(SMALL(A1:A10,9)+SMALL(A1:A10,10))/2 然后{{1}}

  5. 此时我需要一个快速的解决方案。对我来说,第三个是最好的,但它没有给出完全相同的结果。

    在我回到选项2之前有没有人有任何想法,这有点乱?

1 个答案:

答案 0 :(得分:1)

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

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

  1. 我下载了Apache POI 3.9的源代码
  2. 我在src / resources / main / org / apache / poi / ss / formula / function / functionMetadata.txt(or online)中检查了PERCENTILE函数的ID号,它是328
  3. 我这样补充道 retval[328] = AggregateFunction.PERCENTILE; 到文件org.apache.poi.ss.formula.eval.FunctionEval.java
  4. 我补充说 public static final Function PERCENTILE = new Percentile();到适当位置的文件org.apache.poi.ss.formula.functions.AggregateFunction.java。
  5. 我在同一个文件中添加了以下代码(我基于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);
    }
    

    }

  6. 然后我分别上传了这两个文件,然后可以正常使用PERCENTILE功能。