W
W
Wan-Derer2020-09-04 22:04:38
Java
Wan-Derer, 2020-09-04 22:04:38

Java, string sorting. How right?

Greetings! Faced a strange problem. Description and question in code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test1825 {
    public static void main(String[] args) {
// Есть несортированный массив строк, содержащих числовые окончания
// (для простоты оставил только сами числа)
// Хочу их вывести в порядке возрастания числа:
// 1, 2, 5, 6, 11, 15, 21, 25, 55
// Пробую сортировать:
        String[] s = {"5", "2", "11", "1", "21", "55", "15", "25", "6"};
        Arrays.sort(s);
        System.out.println(Arrays.toString(s));
// Результат: [1, 11, 15, 2, 21, 25, 5, 55, 6]
// наверно, предсказуем, но пробую через коллекцию:

        List<String > list = new ArrayList<>(Arrays.asList("5", "2", "11", "1", "21", "55", "15", "25", "6"));
        list.sort(String::compareTo);
        System.out.println(list);
// Результат тот же. Логично, ведь взят штатный компаратор от String.
// Хорошо! Пишу свой компаратор, учитывающий длину строки:

        list = Arrays.asList("5", "2", "11", "1", "21", "55", "15", "25", "6");
        list.sort((String a, String b) ->
                {
                    //System.out.println(a + "| " + b + "|"); // контроль
                    int res = 0;
                    char[] arrA = a.toCharArray();
                    char[] arrB = b.toCharArray();
                    int end = Math.min(a.length(), b.length());
                    for (int i = 0; i < end; i++) {
                        res = arrA[i] - arrB[i];
                        if (res != 0) break;
                    }
                    if (res == 0) res = a.length() - b.length();
                    //System.out.println(res);    // контроль
                    return res;
                }
        );
        System.out.println(list);
// Если раскомментировать контрольный вывод: то видно что компаратор отрабатывает правильно,
// т.е. к примеру: 2 < 11
// НО! Результат всё тот же - неправильная сортировка.
// Как сие можно объяснить и как подобные строки сортировать правильно?

    }
}


Tell me what's wrong and how to do it right :)

Answer the question

In order to leave comments, you need to log in

3 answer(s)
D
Denis Zagaevsky, 2020-09-04
@zagayevskiy

All of them are correctly sorted, in lexicographic order. Character by character, '1'<'2' means "100" < "2".
Write a comparator that will count strings as numbers. You roughly did this (wildly suboptimal), but you're comparing the wrong characters. In the case of 100 and 2, you're comparing them against the null character, and only once. Again 1<2. Compare like this only has strings of the same length, otherwise the one with the longer length is greater.

E
EMy, 2020-09-04
@Emiral

Arrays.asList as far as I remember returns an immutable array.

O
Orkhan, 2020-09-04
Hasanly @azerphoenix

Here are 2 sort options:

public class Main {

    private static String[] sArr = {"5", "2", "11", "1", "21", "55", "15", "25", "6"};

    public static void main(String[] args) {
       sortMethod1();
       sortMethod2(sArr);
    }

    /**
     * Метод парсит значения в целочисленный массив, а затем сортирует
     */
    public static void sortMethod1() {
        int[] intArr = Arrays.stream(sArr).mapToInt(Integer::parseInt).toArray();
        Arrays.sort(intArr);
        System.out.println(Arrays.toString(intArr));
    }

    /**
     * Метод парсит массив строк в List. Затем заменяет (удаляет) нечисловые символы и сортирует
     * @param strArr
     */
    public static void sortMethod2(String[] strArr) {
        List<String> stringList = Arrays.asList(strArr);
        Collections.sort(stringList, new Comparator<String>() {
            public int compare(String o1, String o2) {
                return extractInt(o1) - extractInt(o2);
            }

            int extractInt(String s) {
                String num = s.replaceAll("\\D", "");
                return num.isEmpty() ? 0 : Integer.parseInt(num);
            }
        });
        System.out.println(stringList);
    }

}

Execution result:
[1, 2, 5, 6, 11, 15, 21, 25, 55]
[1, 2, 5, 6, 11, 15, 21, 25, 55]

It basically boils down to parsing an array or list of strings into an array or list of strings and then sorting

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question