Как сделать отсортированную таблицу из строк, лежащих в коллекции
У меня есть заполненный лист:
List<String> autoName = new ArrayList<String>();
В нём хранятся значения вида "Daewoo (5312)". Мне нужно вывести таблицу из двух колонок: в одной название марки авто, во второй количество автомобилей (число из скобок), да ещё и так, чтоб она была отсортирована по убыванию!
Ответы (2 шт):
Разделяйте задачу на части, например:
- Парсинг названия, чтобы получить марку и количество. Это легко сделать через регулярные выражения
- Сортировки списка, используя количество, указанное в скобках
- Вывод таблицы
Шаги:
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.
Для упрощения работы, я бы рекомендовал сделать класс с названием марки и количеством, и с ней работать.
Надеюсь, наведет на нужные мысли. Собираем из листа карту и выводим ее:
// пример листа
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