Сортировка строк Apache-POI в excel
Я хотел бы сортировать строки в листе одним столбцом строки. Я пытался добиться этого, используя метод Sheet.shiftRows, но с этим я не могу справиться. Он не переключает позиции строк в моем методе. Что не так в моем коде? Или, может быть, есть лучший способ сортировки строк любым столбцом String в excel?
/**
* Sorts (A-Z) rows by String column
* @param sheet - sheet to sort
* @param column - String column to sort by
* @param rowStart - sorting from this row down
*/
private void sortSheet(Sheet sheet, int column, int rowStart) {
boolean sorting = true;
int lastRow = sheet.getLastRowNum();
while (sorting == true) {
sorting = false;
for (Row row : sheet) {
// skip if this row is before first to sort
if (row.getRowNum()<rowStart) continue;
// end if this is last row
if (lastRow==row.getRowNum()) break;
Row row2 = sheet.getRow(row.getRowNum()+1);
if (row2 == null) continue;
String firstValue = (row.getCell(column) != null) ? row.getCell(column).getStringCellValue() : "";
String secondValue = (row2.getCell(column) != null) ? row2.getCell(column).getStringCellValue() : "";
//compare cell from current row and next row - and switch if secondValue should be before first
if (secondValue.compareToIgnoreCase(firstValue)<0) {
sheet.shiftRows(row2.getRowNum(), row2.getRowNum(), -1);
sheet.shiftRows(row.getRowNum(), row.getRowNum(), 1);
sorting = true;
}
}
}
}
Любая идея, как управлять сортировкой строк в листе?
ОБНОВЛЕНИЕ. Метод выше работает с версии Apache-POI 3.9.
РЕДАКТИРОВАТЬ: Добавлена отсутствующая скобка -helvio
Ответы
Ответ 1
Теперь я теперь почему это не работает. В методе shiftRows есть ошибка. Когда третий аргумент (число сдвига строк) отрицательный, это вызывает проблемы.
Это описано здесь: https://issues.apache.org/bugzilla/show_bug.cgi?id=53798
UPDATE
Эта ошибка исправлена из версии 3.9
Ответ 2
У Poi нет встроенного механизма сортировки, хотя, конечно, вы далеки от первого с этой потребностью.
Я думаю, что у вас проблемы, потому что вы перемещаете строки, которые вы повторяете. Я запустил код выше, и кажется, что происходит то, что строки исчезают с листа по окончании выполнения кода.
Вопрос пытается сделать модификацию листа для чтения на месте. Я считаю, что создание второго выходного листа было бы более уместным.
Таким образом, базовый подход будет читаться на листе, сортировать в java так же, как вы будете рассматривать любую другую проблему сортировки, записывать в выходной лист. Если вы сделали карту номера строки, которая уникальна для строкового значения интересующего вас столбца, вы можете отсортировать карту по значению. Такой подход будет работать, если вы только предвидите необходимость сортировки по одному столбцу. В любом случае, это не так просто, как просто выбрать опцию меню сортировки из excel.
Ответ 3
Для сортировки строк необходимо:
- скопировать все строки в темп
- сортировать строки в темп
- удалить все строки с листа
- создавать новые строки со значениями отсортированных строк из temp
Код:
import org.apache.commons.compress.utils.Lists;
import org.apache.poi.hssf.usermodel.HSSFOptimiser;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
public static void sortSheet(Workbook workbook, Sheet sheet) {
//copy all rows to temp
List<Row> rows = Lists.newArrayList(sheet.rowIterator());
//sort rows in the temp
rows.sort(Comparator.comparing(cells -> cells.getCell(0).getStringCellValue()));
//remove all rows from sheet
removeAllRows(sheet);
//create new rows with values of sorted rows from temp
for (int i = 0; i < rows.size(); i++) {
Row newRow = sheet.createRow(i);
Row sourceRow = rows.get(i);
// Loop through source columns to add to new row
for (int j = 0; j < sourceRow.getLastCellNum(); j++) {
// Grab a copy of the old/new cell
Cell oldCell = sourceRow.getCell(j);
Cell newCell = newRow.createCell(j);
// If the old cell is null jump to next cell
if (oldCell == null) {
newCell = null;
continue;
}
// Copy style from old cell and apply to new cell
CellStyle newCellStyle = workbook.createCellStyle();
newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
newCell.setCellStyle(newCellStyle);
// If there is a cell comment, copy
if (oldCell.getCellComment() != null) {
newCell.setCellComment(oldCell.getCellComment());
}
// If there is a cell hyperlink, copy
if (oldCell.getHyperlink() != null) {
newCell.setHyperlink(oldCell.getHyperlink());
}
// Set the cell data type
newCell.setCellType(oldCell.getCellType());
// Set the cell data value
switch (oldCell.getCellType()) {
case BLANK:
newCell.setCellValue(oldCell.getStringCellValue());
break;
case BOOLEAN:
newCell.setCellValue(oldCell.getBooleanCellValue());
break;
case ERROR:
newCell.setCellErrorValue(oldCell.getErrorCellValue());
break;
case FORMULA:
newCell.setCellFormula(oldCell.getCellFormula());
break;
case NUMERIC:
newCell.setCellValue(oldCell.getNumericCellValue());
break;
case STRING:
newCell.setCellValue(oldCell.getRichStringCellValue());
break;
}
}
// If there are are any merged regions in the source row, copy to new row
for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
CellRangeAddress cellRangeAddress = sheet.getMergedRegion(j);
if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) {
CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(),
(newRow.getRowNum() +
(cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow()
)),
cellRangeAddress.getFirstColumn(),
cellRangeAddress.getLastColumn());
sheet.addMergedRegion(newCellRangeAddress);
}
}
}
}
private static void removeAllRows(Sheet sheet) {
for (int i = 0; i < sheet.getLastRowNum(); i++) {
sheet.removeRow(sheet.getRow(i));
}
}