Как сделать отсортированную таблицу из строк, лежащих в коллекции

У меня есть заполненный лист:

List<String> autoName = new ArrayList<String>();

В нём хранятся значения вида "Daewoo (5312)". Мне нужно вывести таблицу из двух колонок: в одной название марки авто, во второй количество автомобилей (число из скобок), да ещё и так, чтоб она была отсортирована по убыванию!


Ответы (2 шт):

Автор решения: gil9red

Разделяйте задачу на части, например:

  1. Парсинг названия, чтобы получить марку и количество. Это легко сделать через регулярные выражения
  2. Сортировки списка, используя количество, указанное в скобках
  3. Вывод таблицы

Шаги:

0. Исходный список:

List<String> autoNames = new ArrayList<>();
autoNames.add("Daewoo (5312)");
autoNames.add("ABC (590)");
autoNames.add("Foo (3000)");
autoNames.add("Bar (1)");

1. Составление функции парсинга. Нужно уметь извлекать название марки и количество. Для этого заводим регулярные выражения:

public static Pair<String, Integer> parseAutoName(String autoName) {
    Matcher match = Pattern.compile("(.+?) \\((\\d+)\\)").matcher(autoName);
    if (!match.find()) {
        return new Pair<>(null, 0);
    }

    return new Pair<>(match.group(1), Integer.valueOf(match.group(2)));
}

Тестирование:

for (String autoName : autoNames) {
    System.out.println(autoName + " -> " + parseAutoName(autoName));
}
// Daewoo (5312) -> Daewoo=5312
// ABC (590) -> ABC=590
// Foo (3000) -> Foo=3000
// Bar (1) -> Bar=1

2. Сортировка по убыванию:

autoNames.sort((obj1, obj2) -> parseAutoName(obj2).getValue().compareTo(parseAutoName(obj1).getValue()));

for (String autoName : autoNames) {
    System.out.println(autoName);
}
// Daewoo (5312)
// Foo (3000)
// ABC (590)
// Bar (1)

Для сортировки по возрастанию достаточно compareTo вызвать у obj1 к obj2

3. Вывод данных. Самый простой вариант -- использование форматирование с заполнением пробелами до указанной длины (%10s тут до 10 символов будет добита строка):

System.out.println(String.format("%10s %s", "NAME", "NUMBER"));
for (String autoName : autoNames) {
    Pair<String, Integer> pair = parseAutoName(autoName);
    System.out.println(String.format("%10s %s", pair.getKey(), pair.getValue()));
}
//       NAME NUMBER
//     Daewoo 5312
//        Foo 3000
//        ABC 590
//        Bar 1

Все вместе:

public static Pair<String, Integer> parseAutoName(String autoName) {
    Matcher match = Pattern.compile("(.+?) \\((\\d+)\\)").matcher(autoName);
    if (!match.find()) {
        return new Pair<>(null, 0);
    }

    return new Pair<>(match.group(1), Integer.valueOf(match.group(2)));
}

public static void main(String[] args) throws Exception {
    List<String> autoNames = new ArrayList<>();
    autoNames.add("Daewoo (5312)");
    autoNames.add("ABC (590)");
    autoNames.add("Foo (3000)");
    autoNames.add("Bar (1)");

    autoNames.sort((obj1, obj2) -> parseAutoName(obj2).getValue().compareTo(parseAutoName(obj1).getValue()));

    System.out.println(String.format("%10s %s", "NAME", "NUMBER"));
    for (String autoName : autoNames) {
        Pair<String, Integer> pair = parseAutoName(autoName);
        System.out.println(String.format("%10s %s", pair.getKey(), pair.getValue()));
    }
}

PS.

Для упрощения работы, я бы рекомендовал сделать класс с названием марки и количеством, и с ней работать.

→ Ссылка
Автор решения: Podushkoved

Надеюсь, наведет на нужные мысли. Собираем из листа карту и выводим ее:

// пример листа
List<String> autoName = new ArrayList<>() {{
    add("Daewoo (5312)");
    add("Asdfgh (23)");
    add("Qwerty (5467)");
    add("Zxcvb (324)");
}};

autoName.stream()
    // собираем из листа карту Map<Integer, String>
    .collect(Collectors.toMap(
        // ключ карты - цифры, поэтому
        // все, что не цифры, убираем
        entry -> Integer.parseInt(entry.replaceAll("\\D", "")),
        // значение карты - строка, поэтому
        // убираем цифры, пробелы и скобки
        entry -> entry.replaceAll("[\\d\\s()]", ""),
        // функция суммирования строк
        // с одинаковым ключом
        (s1, s2) -> s1 + " " + s2,
        // тип коллекции TreeMap
        // с сортировкой по убыванию
        () -> new TreeMap<Integer, String>(Comparator.reverseOrder())))
    // обходим карту и
    // выводим результат
    .forEach((key, value) -> System.out.println(value + " " + key));

Вывод:

Qwerty 5467
Daewoo 5312
Zxcvb 324
Asdfgh 23
→ Ссылка