Сортировка строк 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));
            }
        }