- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在 xlsx 工作簿中,有一些单元格带有一些无界 SUMIF 公式,如下所示:SUMIF(MySheetname!$B:$B,$E4,MySheetname!$I:$I)
.
使用 Apache POI 5.0.0 对一个 SUMIF 函数的评估持续 100 毫秒,而对给定工作簿的评估持续几分钟。
改进执行持续时间的一种方法是将公式绑定(bind)到如下内容:SUMIF(MySheetname!$B1:$B100,$E4,MySheetname!$I1:$I100)
.在我的情况下,这不是一个解决方案,因为我不是 xlsx 文件的作者,并且系统从未知的人那里获取未知的 xlsx 文件(所以我不能只是告诉他们限制 SUMIF 范围)。org.apache.poi.ss.formula.functions.Sumif
的当前执行情况迭代给定(无界)范围内的所有单元格,因此每次评估都会迭代 1048576 个单元格。
这是方法 sumMatchingCells(AreaEval, I_MatchPredicate, AreaEval)
实现的一部分:
for (int r=0; r<height; r++) {
for (int c=0; c<width; c++) {
result += accumulate(aeRange, mp, aeSum, r, c);
}
}
我想通过检查行或列是否实际存在于总和范围内来提高此方法的性能。也许是这样的(使用不存在的方法
sheetContainsRowIndex
):
for (int r = 0; r < height; r++) {
if (aeSum.sheetContainsRowIndex(aeSum.getFirstRow() + r)) {
for (int c = 0; c < width; c++) {
if (aeSum.sheetContainsColumnIndex(aeSum.getFirstColumn() + c)) {
[...]
LazyAreaEval
包含
SheetRangeEvaluator
这包含
SheetRefEvaluator
s 并且这些包含
EvaluationSheet
这至少知道
getLastRowNum()
.不幸的是,这个属性链是私有(private)的。
最佳答案
修补 apache poi
公式评估需要深入了解来源,并在评估过程中进行翻找。那不是我会做的。
但解决方法可能是在评估之前将公式中的所有完整列引用替换为从第 1 行到工作表中最后一行的区域引用。
如果您只阅读工作簿,那么这只会影响随机存取内存,而不会影响存储的文件。当然,如果您需要保存更改后的工作簿,那么它会影响存储的文件。那么该解决方法可能无法使用。
当工作表中有多个具有完整列引用的公式时,这对过程持续时间有显着影响,至少使用 *.xlsx
( XSSF
) 并且虽然需要为每个公式执行额外的替换过程。
完整代码示例:
import java.io.FileInputStream;
import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.ptg.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.SpreadsheetVersion;
public class ExcelEvaluateFullColumnFormulas {
private static String replaceFullColumnReferences(XSSFSheet sheet, String formula) {
//System.out.println(formula);
XSSFWorkbook workbook = sheet.getWorkbook();
XSSFEvaluationWorkbook evaluationWorkbook = XSSFEvaluationWorkbook.create(workbook);
Ptg[] ptgs = FormulaParser.parse(formula, (FormulaParsingWorkbook)evaluationWorkbook,
FormulaType.CELL, sheet.getWorkbook().getSheetIndex(sheet));
for (int i = 0; i < ptgs.length; i++) {
if (ptgs[i] instanceof AreaPtgBase) { // the operand Ptg is an area reference
AreaPtgBase ref = (AreaPtgBase) ptgs[i];
if (ref.getFirstRow() == 0 && ref.getLastRow() == SpreadsheetVersion.EXCEL2007.getLastRowIndex()) { // only for full column area references
int lastRowInSheet = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
if (ref instanceof Area2DPtgBase) { // the area reference is a 2D area reference in same sheet
lastRowInSheet = sheet.getLastRowNum(); // get last row of this sheet
} else if (ref instanceof Area3DPxg) { // the area reference is a 3D area reference in another sheet
Area3DPxg ref3D = (Area3DPxg)ref;
String sheetName = ref3D.getSheetName();
lastRowInSheet = workbook.getSheet(sheetName).getLastRowNum(); // get last row of referenced sheet
}
ref.setLastRow(lastRowInSheet);
formula = FormulaRenderer.toFormulaString((FormulaRenderingWorkbook)evaluationWorkbook, ptgs);
}
}
}
//System.out.println(formula);
return formula;
}
public static void main(String[] args) throws Exception {
DataFormatter formatter = new DataFormatter();
Workbook workbook = WorkbookFactory.create(new FileInputStream("test.xlsx"));
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Sheet sheet = workbook.getSheetAt(0);
java.time.LocalDateTime startTime = java.time.LocalDateTime.now();
for (Row row : sheet) {
for (Cell cell : row) {
///*
if (cell.getCellType() == CellType.FORMULA) {
if (sheet instanceof XSSFSheet){ // do it for XSSF only, not necessary for HSSF.
String formula = cell.getCellFormula();
formula = replaceFullColumnReferences((XSSFSheet)sheet, formula);
cell.setCellFormula(formula);
}
}
//*/
String value = formatter.formatCellValue(cell, evaluator);
System.out.print(value + "\t");
}
System.out.println();
}
java.time.LocalDateTime endTime = java.time.LocalDateTime.now();
java.time.Duration duration = java.time.Duration.between(startTime, endTime);
System.out.println("process duration: " + duration);
workbook.close();
}
}
注释掉部分
...
/*
if (cell.getCellType() == CellType.FORMULA) {
if (sheet instanceof XSSFSheet){ // do it for XSSF only, not necessary for HSSF.
String formula = cell.getCellFormula();
formula = replaceFullColumnReferences((XSSFSheet)sheet, formula);
cell.setCellFormula(formula);
}
}
*/
...
看到差异。
关于apache-poi - 加速 Apache POI SUMIF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67332225/
我对条件总和有点头疼。环顾四周,但似乎不太明白。 这是我的逻辑: 如果 A2 包含字母 P 以外的任何内容,我想在 D2 中返回 =B2-C2。 但是,如果 A2 包含字母 P,我想在 D2 中返回
我试图通过在 SUMIF 函数中使用条件列表来简化 SUMIFS 公式。然而,我的 SUMIF 公式似乎只考虑第一个标准。我缺少什么?请参阅下面的图像和公式。 =SUMIFS(C1:C10,B1:B1
我需要通过单元格引用传递一个多标准列表(一个常量数组),而不是将其硬输入到我的公式中。 所以,而不是这个:=SUM(SUMIFS(sum_range,criteria_range,{"red","bl
我正在尝试创建一个电子表格,该电子表格允许我根据某个单元格(“A36”)是否相当于“N95”或“N64”以及范围(G35:G46)来发送电子邮件等于或大于“56”。我过去通过使用 IF(SUMIF()
所以我有以下公式: =sumif(Gx:Gy,50,Px:Py) 其中 x 和 y 是我输入的数字。 但是,我希望上述公式中的数字由另一个单元格中的值确定(假设 x 由单元格 A1 中的值确定,y 由
尝试使用 SUMIFS、INDEX 和 MATCH 的组合,但公式仅返回第一列的值并忽略共享相同字段的后续列。请问我可以用什么公式来解决这个问题? A B C
我遇到错误代码 1004 的问题。我试图在我的 VBA 代码中使用 SUMIF 公式。我的目标是将 F2 中的 F 列求和到最后一行。该列的 Vlookup 值包括“#N/A”。没有 VBA 使用的公
我为我的工作创建了时间日志: 为了更好地说明,我附上图片如下: 其中 start 和 end 是我在 A 列中启动特定任务的时间,delta 是 End 和 Start 中的值之间的差异。 在下一张表
我在 Worksheet1 上的当前公式如下: SUMIF(Setup!$C$5:$C$375,"C-R",'PMS Input'!$K$13:$K$416) 在设置工作表上,我已确认 C 列中只有一
我对 VBA 很陌生,所以请在这里耐心等待。 我需要根据几个列标题进行总和,这些列放置的位置总是不同的(例如,FRT 列可能一次位于 B 列,另一次位于 D 列)。 然而,这三个组件总是相同的,但可以
在 excel 中,我希望从该数字开始计算列中每个数字的倒数之和。 下面工作正常: 例如:第二列中每个单元格的以下公式 =SUM(1/A1:A6) =SUM(1/A2:A6) . . 但是,如果我有一
我正在尝试在 excel 中使用 SUMIFS() 公式从表中排除某些行,但条件范围包括存储为文本的数字。 在下图中,我想排除实体 ID 为“101000”的行。我尝试过的 SUMIFS() 公式都提
我想要一个 sumifs 公式,它指的是可能变量的列表,即不同的帐号。我更愿意这样做,而不是像个人那样硬编码 如此有效地为每个帐户代码做一个 sumifs 并将它们添加到一个单元格中。我知道我可以有效
我有一个如下表: X 1 X 3 X 2 Y 2 Y 5 Z 3 Z 4 我知道我可以使用 SUMIF 来计算第一列中每个值的第二列的总和,例如 =SUMIF(A1:A7,"X",B1:B7) 会给我
嗨,你们这些了不起的人 更新 你知道吗,我应该让你知道我实际上是在尝试用数字而不是字母来做到这一点。例如,我有一个值为 225566 的字段,我正在尝试挑选其中包含 55 的字段。直到现在我才意识到这
我正在尝试汇总 D 列中在主要或次要类别中为"is"的所有数据,但仅包括该值的第一个实例。在下面的示例中,总和为 3(A 为 1,B 为 2)。请帮忙!! Area Primary Site
这个问题在这里已经有了答案: SUMIF with OR criteria (5 个回答) 5年前关闭。 我试图找出一个 SUMIFS 公式,其中多标准范围可能包含也可能不包含零。以下表为例。 |Ti
我正在尝试创建一个 SumIf 公式,该公式根据一个标准将多个列添加在一起。 =sumif(F$8:F$58,F73,L$8:L$58+I$8:I$58) 这给了我一个错误,并且不会将两列加在一起。
我有一张这样的 table : #+NAME: ENTRY |------+--------| | Item | Amount | |------+--------| | A | 100
我有一组数据,如果员工属于某个组,我想在其中添加工资金额。 现在,有 8 个组 A 到 H,我可以使用 sumifs 排除 E 到 H,如下所示: =SUMIFS($Q$3:$Q$119,$M$3:$
我是一名优秀的程序员,十分优秀!