Читать данные как массивы из текстового файла в Java - PullRequest
1 голос
/ 24 октября 2019

У меня есть текстовый файл с набором массивов с определенным номером, который я должен найти в массиве. Текстовый файл выглядит следующим образом:

(8) {1, 4, 6, 8, 12, 22}
(50) {2, 5, 6, 7, 10, 11, 24, 50, 65}
(1) {1}
(33) {1, 2, 5, 6, 11, 12, 13, 21, 25, 26, 30, 33, 60, 88, 99}
(1) {1, 2, 3, 4, 8, 9, 100}
(1) {2, 3, 5, 6, 11, 12, 13, 21, 25, 26, 30, 33, 60, 88, 99}

, где число в скобках - это число, которое я должен найти с помощью бинарного поиска. а остальное это фактический массив. Я не знаю, как я мог бы получить этот массив из текстового файла и быть в состоянии прочитать его как фактический массив. [Это вопрос о предыдущем конкурсе по программированию, который я принимал, и обдумываю проблемы]

У меня уже есть метод для бинарного поиска, и я использовал сканер для чтения файла следующим образом:

Scanner sc = new Scanner(new File("search_race.dat"));

и использовал цикл while, чтобы иметь возможность перебирать файл и читать его.

Но я застрял на том, как заставить java узнать, что содержимое в фигурных скобках являетсямассив и прочее в круглых скобках - это то, для чего он должен использовать бинарный поиск по указанному массиву.

Ответы [ 4 ]

1 голос
/ 25 октября 2019

Вы можете просто проанализировать каждую строку (число и массив) следующим образом:

while (sc.hasNext()) {
    int numberToFind = Integer.parseInt(sc.next("\\(\\d+\\)").replaceAll("[()]", ""));

    int[] arrayToFindIn  = Arrays.stream(sc.nextLine().split("[ ,{}]"))
                                        .filter(x->!x.isEmpty())
                                        .mapToInt(Integer::parseInt)
                                        .toArray();

    // Apply your binary search ! Craft it by yourself or use a std one like below :
    // int positionInArray = Arrays.binarySearch(arrayToFindIn, numberToFind);
}

Если вам не нравится replaceAll, вы можете заменить первую строку в цикле надва ниже:

    String toFindGroup = sc.next("\\(\\d+\\)");
    int numberToFind = Integer.parseInt(toFindGroup.substring(1, toFindGroup.length()-1));

Ура!

1 голос
/ 24 октября 2019

TL; DR: Вы должны проверять символ за символом и видеть, является ли это фигурная скобка или скобка или цифра

Длинный ответ:
Сначала создайте POJO (давайте назовем это AlgoContainer, но используем любое имя, которое вам нравится) с полями int numberToFind и ArrayList<Integer> listOfNumbers.
Затем прочитайте файл, как @ ManojBanik, упомянутый вкомментарии

Теперь создайте ArrayList<AlgoContainer> (его размер должен совпадать с ArrayList<String>, полученным при чтении файла построчно)

Затем выполните цикл по ArrayList<String> на предыдущем шаге и выполните следующие операции:

  1. Создайте и создайте экземпляр экземпляра объекта AlgoContainer (давайте назовем это tempAlgoContainer).

  2. проверить, является ли первый символ открытыми скобками -> да? создать пустую переменную temp String -> проверить, является ли следующий символ числом -> yes? -> добавить его к пустому String и повторять, пока не найдете закрывающую скобку.

  3. Нашли открытые скобки? разберите temp String на int и установите для поля numberToFind значение tempAlgoContainer для этого числа.

  4. Далее идет вопрос о фигурных скобках: нашли фигурные скобки? создать новый пустой темп String -> проверить, является ли следующий символ цифрой -> да? добавить, затем добавить его к пустому String, как на шаге 2, пока не найдете запятую или закрывающую фигурную скобку.

  5. Нашли запятую? проанализируйте temp String в int, а затем добавьте его к listOfNumbers (который является полем) tempAlgoContainer -> снова сделайте пустым temp String.
  6. Нашли закрывающую фигурную скобку? повторите вышеуказанный шаг и вырвитесь из цикла. Теперь вы готовы обрабатывать все, что хотите. Ваши данные готовы.

Кроме того, неплохо бы иметь функцию-член или метод экземпляра AlgoContainer (вызывайте его как хотите) для выполнения двоичного поиска, чтобы вы могли просто выполнить цикл по ArrayList<AlgoContainer>и вызовите эту функцию BS (не предназначенную для каламбура)

1 голос
/ 24 октября 2019

Чтобы прочитать файл, вы можете использовать Files.readAllLines()

Чтобы фактически проанализировать каждую строку, вы можете использовать что-то вроде этого.

Во-первых, чтобы упростить задачу, удалите все пробелы изстрока.

line.replaceAll("\\s+", "");

Это по существу преобразует (8) {1, 4, 6, 8, 12, 22} в (8){1,4,6,8,12,22}.

Далее, используйте регулярное выражение для проверки строки. Если строка не совпадает, дальнейшие действия не требуются.

Выражение: \([0-9]*\)\{[0-9]*(,[0-9]*)*}

  • \([0-9]*\) относится к (8) (приведенный выше пример)
  • \{[0-9]*(,[0-9]*)*} относится к {1,4,6,8,12,22}

Если вы не понимаете выражения, зайдите здесь .

Наконец, мы можем разобрать строку вего два компонента: число для поиска и int[] с фактическими значениями.

// start from index one to skip the first bracket
int targetEnd = trimmed.indexOf(')', 1);
String searchString = trimmed.substring(1, targetEnd);
// parsing wont throw an exception, since we checked with the regex its a number
int numberToFind = Integer.parseInt(searchString);

// skip ')' and '{', align to the first value, skip the last '}'
String valuesString = trimmed.substring(targetEnd + 2, trimmed.length() - 1);
// split the array at ',' to get each value as string
int[] values = Arrays.stream(valuesString.split(","))
    .mapToInt(Integer::parseInt).toArray();

После анализа обоих этих компонентов вы можете выполнить двоичный поиск самостоятельно.

Примеркод как Gist на GitHub

1 голос
/ 24 октября 2019

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

Ниже регулярное выражение должно соответствовать строке

\((\d+)\) \{([\d, ]+)\}

Тогда группа (1) выдаст цифру в скобках (в виде строки), а группа (2) - строку в фигурных скобках, которые можно разделить с помощью пробела, и пробел (если каждая запятая следует за пробелом). ) и получить массив чисел (снова в виде строк)

Надеюсь, это поможет!

...