#java
Вопрос:
Допустим, у вас есть массив, содержащий строки:
arr1={"sell 1, time 4, item 4", "buy 3, time 2, item 5"}
вы хотите отсортировать элементы по «времени» в порядке возрастания, как это можно сделать? Так что вы бы:
arr1={"buy 3, time 2, item 5", "sell 1, time 4, item 4"}
Может быть, объединить каждую строку и повторять каждый символ, пока не встретите цифру?
Я попытался сделать следующее:
String[] arr1={"sell 1, time 4, item 4", "buy 3, time 2, item 5"}; String singleString = arr1[0]; int indexOfNumber=singleString.indexOf("time") 5; System.out.println(singleString.charAt(indexOfNumber));
Я как-то думаю о цикле for, но не могу придумать, как это сделать.
Комментарии:
1. Разбейте это на более мелкие кусочки. Например, на одном шаге напишем метод, который разберет строку на более значимые фрагменты данных. Затем, после того как у вас будет этот метод, вы сможете применить его к каждой строке в массиве. Затем, наконец, вы можете отсортировать массив.
Ответ №1:
Вы можете использовать API потоков Java.
1. Смоделируйте вещь, с которой вы работаете
Ваша строка, разделенная запятыми, представляет что-то. Что это? Я назвал его ан Event
, со свойствами
- действие, либо покупайте, либо продавайте;
- количество, число, стоящее за действием;
- время, число, стоящее за текстом «время»; и
- товар, номер за текстом «товар».
Теперь вы можете создать модель только с помощью этого:
record Event(String action, int quantity, int time, int item) { }
Примечание: записи доступны с Java 16. Если вы используете более низкую версию Java, то вместо этого вам нужно создать класс. Убедитесь, что вы создали конструктор, принимающий и устанавливающий все поля, и убедитесь, что вы создали геттеры. Обратите внимание, что для записей компилятор автоматически создает методы доступа с тем же именем, что и для полей.
2. Создайте метод, способный анализировать строку в Event
Например, ваша входная строка, по "sell 1, time 4, item 4"
-видимому, имеет фиксированную структуру. Что происходит в приведенном ниже фрагменте кода, так это то, что я предполагаю, что здесь всегда так. Если мы разделимся либо пробелом, либо запятой, за которой следует пробел, то у нас будет шесть элементов (с индексами 0 — 5). Каждый из этих шести элементов содержит часть информации, соответствующую нашей модели:
Event parseEvent(String input) { String[] parts = input.split(",? "); String action = parts[0]; int quantity = Integer.parseInt(parts[1]); int time = Integer.parseInt(parts[3]); int item = Integer.parseInt(parts[5]); return new Event(action, quantity, time, item); }
3. Проведите поток по элементам, преобразуя эти строки, разделенные запятыми, в красивые Event
модели, а затем отсортируйте по time
свойству вашей модели:
Stream.of(arr1) .map(element -gt; parseItem(element)) // Convert string to Event instance .sorted(Comparator.comparing(Event::time)) .forEach(System.out::println);
Комментарии:
1. FWIW, вы можете использовать ссылку на метод
this::parseItem
вместо лямбды. Не держи меня за это, но я думаю, что конвенция о кодировании предпочитает первое второму.
Ответ №2:
вы можете использовать регулярное выражение, чтобы получить число, следующее даст вам число в виде строки "time (d)"
, которую вы затем можете отсортировать
Ответ №3:
Если имена строк имеют постоянную длину (они указаны в вашем примере), то вы можете просто подсчитать количество символов и использовать значение времени для сортировки. Например, первое значение времени начинается с индекса 14. Если имена не имеют постоянной длины, вы можете использовать регулярное выражение для извлечения значения времени из каждой строки. Кроме того, вы также можете разделить каждую строку разделителем ,
, а затем снова разделить 2-й элемент пробелом и выбрать последний элемент.
Ответ №4:
Для сортировки массива используйте Arrays.sort
с помощью a Comparator
. В вашем случае сравнение выполняется в поле, которое вы найдете с регулярным выражением.
Так:
Pattern timePattern = Pattern.compile("time (\d )"); Functionlt;String,Integergt; getTime = s -gt; { Matcher matcher = timePattern.matcher(s); return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; }; Comparatorlt;Stringgt; sortByTime = Comparator.comparingInt(getTime);
Затем вы можете отсортировать массив следующим образом:
Arrays.sort(array, sortByTime);
Ответ №5:
Я бы сделал это следующим образом.
String[] arr1 = { "sell 2, time 3", "sell 1, time 4, item 4", "buy 3, time 2, item 5", "sell 6, time 1, item 8" };
- во-первых, используйте
AbstractMap.SimpleEntry
* для хранения строки и критериев сортировки. - затем выполните сортировку по
value
части записи. - извлеките
key
часть - и возвращайтесь в виде массива.
arr1 = Arrays.stream(arr1).map( str -gt; new AbstractMap.SimpleEntrylt;String, Integergt;( str, extract(str))) .sorted(Entry.comparingByValue(Integer::compare)) .map(Entry::getKey).toArray(String[]::new); for (String s : arr1) { System.out.println(s); }
С принтами
sell 6, time 1, item 8 sell 3, time 2, item 5 sell 2, time 3, item 9 sell 1, time 4, item 4
Вот вспомогательный метод для извлечения time
значения.
- используйте регулярное выражение для записи определенного значения поля
- и возвращайтесь в виде целого числа.
public static Integer extract(String str) { Matcher m = Pattern.compile("time\s (\d )").matcher(str); m.find(); return Integer.valueOf(m.group(1)); }
* Для больших списков я предпочитаю использовать Entry
метод, так extract
как метод вызывается только один раз для каждого значения, а не для каждого сравнения.