Я работаю над приложением, которое читает файл Excel с Apache POI. Я поместил значение ячейки в матрицу объекта String.

[title 1][title 2][title 3]
[mark]   [smith]  [34]
[simon]  [black]  [24]

Меня попросили разрешить упорядочить матрицу по выбранному столбцу. Как я могу заказать матрицу объекта String?

Спасибо

-2
MDP 28 Май 2019 в 11:33

2 ответа

Лучший ответ

Если у вас всего несколько столбцов, вы можете создать несколько компараторов со значимым именем и отсортировать их, как показано ниже:

    public static void main(String[] args) {
    String[][] matrix = {{"mark","smith","34"},
                         {"simon","black","24"},
                         {"foo","bar","44"}
                        };        

    Comparator<String[]> firstNameComparator  = new Comparator<String[]>() {
        @Override
        public int compare(String[] row1, String[] row2) {
            return row1[0].compareTo(row2[0]);
        }
    };
    Comparator<String[]> lastNameComparator  = new Comparator<String[]>() {
        @Override
        public int compare(String[] row1, String[] row2) {
            return row1[1].compareTo(row2[1]);
        }
    };
    Comparator<String[]> ageComparator  = new Comparator<String[]>() {
        @Override
        public int compare(String[] row1, String[] row2) {
            return Integer.compare(Integer.parseInt(row1[2]), Integer.parseInt(row2[2]));
        }
    };
    Arrays.sort(matrix, firstNameComparator);// pass the desired comparator
    for(String[] row:matrix){
        System.out.println(Arrays.toString(row));
    }
}

Или создайте класс, который расширяет Comparator и передает индекс столбца:

public class NewClass5 {
    public static void main(String[] args) {
        String[][] matrix = {{"mark","smith","34"},
                             {"simon","black","24"},
                             {"foo","bar","44"}
                            }; 

        Arrays.sort(matrix, new CompareByColumn(1));// pass the desired index
        for(String[] row:matrix){
            System.out.println(Arrays.toString(row));
        }
    }
    static class CompareByColumn implements Comparator {
        int columnToSort;
        CompareByColumn(int columnToSort) {
            this.columnToSort = columnToSort;
        }
        public int compare(Object o1, Object o2) {
                String[] row1 = (String[]) o1;
                String[] row2 = (String[]) o2;
                return row1[columnToSort].compareTo(row2[columnToSort]);
        }
    }    
}

С java 8 и потоками вы можете написать это еще более компактно:

String[][] sorted = Arrays.stream(matrix)
                          .sorted((s1,s2)->s1[1].compareTo(s2[1])) // pass the desired index
                          .toArray(String[][]::new);
for(String[] row: sorted){
    System.out.println(Arrays.toString(row));
}

< Сильный > ИЗМЕНИТЬ

Поскольку вы предпочитаете потоковый подход, я только переработал этот. Но вы можете использовать его и для других подходов. Перед сравнением вы можете проверить, содержит ли соответствующий столбец числа, и выполнить сравнение в простом if-else для чисел или строк.

    int colIndex  = 2;
    String[][] sorted = Arrays.stream(matrix).sorted((s1,s2)-> {
                            if(s1[colIndex].matches("(\\d+(?:\\.\\d+)?)")){
                                return Double.compare(Double.parseDouble(s1[colIndex]), Double.parseDouble(s2[colIndex]));
                            }
                            else{
                                return s1[2].compareTo(s2[2]);
                            }}) 
                      .toArray(String[][]::new);

    for(String[] row: sorted){
        System.out.println(Arrays.toString(row));
    }

Использовал это (\d+(?:\.\d+)?) регулярное выражение для сопоставления как целых чисел, так и чисел с плавающей точкой.

3
Eritrean 28 Май 2019 в 16:05

Прежде всего, спасибо за этот вопрос, это оказалось довольно сложной задачей для визуализации и реализации этого решения. Я надеюсь, что следующее решение - то, что вы хотели.

Я написал метод, который будет сортировать матрицу для вас. Метод принимает матрицу String в качестве аргумента и возвращает новую матрицу String, в которой каждый столбец отсортирован по алфавиту более старому. Сортировка выполняется независимо от других столбцов, поэтому каждый столбец сортируется без внешнего контекста.

К сожалению, это не исключает названия из процесса сортировки, поэтому, если вам нужно, чтобы это произошло, пожалуйста, дайте мне знать, и я сделаю все возможное, чтобы реализовать это.

public static boolean isNumeric(String str) {
    return str.matches("^[0-9]+$");
}

public static String[][] sortMatrix(String[][] matrix)
{
    int matrixLength = matrix[0].length;

    String[][] sortedMatrix = new String[matrixLength][];
    java.util.List<String[]> columns = new java.util.ArrayList<>();

    for (int i1 = 0; i1 < matrixLength; i1++)
    {
        String[] column = new String[matrixLength];
        for (int i2 = 0; i2 < matrixLength; i2++) {
            column[i2] = matrix[i2][i1];
        }
        columns.add(column);
    }

    // First sort the column before proceeding
    columns.forEach(column -> Arrays.sort(column, new Comparator<String>()
    {
        public int compare(String s1, String s2)
        {
            boolean i1 = isNumeric(s1);
            boolean i2 = isNumeric(s2);

            if (i1 && i2) {
                return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
            }
            else if (!i1) {
                return 1;
            }
            else return -1;
        }
    }));

    for (int i1 = 0; i1 < columns.size(); i1++)
    {
        String[] row = new String[matrixLength];
        for (int i2 = 0; i2 < matrixLength; i2++) {
            row[i2] = columns.get(i2)[i1];
        }
        sortedMatrix[i1] = row;
    }
    return sortedMatrix;
}

public static void main(String[] args) throws IOException {

    String[][] matrix = new String[3][] ;
    matrix[0] = new String[] { "title 1", "title 2", "title 3" };
    matrix[1] = new String[] { "simon", "1", "10" };
    matrix[2] = new String[] { "mark", "35", "2" };

    matrix = sortMatrix(matrix);
    for (String[] row : matrix) {
        System.out.println(Arrays.toString(row));
    }
}

РЕДАКТИРОВАТЬ . Внедрил собственный компаратор, учитывающий число.

2
Matthew 28 Май 2019 в 15:39