Как заполнить многомерный список массивов (Java) из текстового файла?

Я хотел бы создать динамический многомерный список ArrayList, который считывается из текстового файла с целыми числами, разделенными пробелами, и строками, выглядящими примерно так:

0 -5 5 0 -3 0 5
3 1 0 0 0 0 5
5 -5 0 5 5 1 1

(Только небольшая часть фактических данных, а строки и столбцы могут быть изменены, поэтому необходим динамический 2D ArrayList.)

Пока это то, что у меня есть в коде:

ArrayList<ArrayList<Integer>> ratings2DArray = new ArrayList<ArrayList<Integer>>();
try {
in = new BufferedReader(new FileReader("PureRatings.txt"));
        int counter = 0;

        while (in.readLine() != null) {
            ratings2DArray.add(new ArrayList<Integer>()); //Adds 2nd dimension. 

^ Практически говоря, что для каждой строки в текстовом файле добавьте строку в 2D ArrayList.

Здесь мне нужно объявить строковую (или символьную?) переменную с именем rating, которая берет ввод из текстового файла. И пусть он будет разделен пробелами (извините, если я неправильно использую терминологию), чтобы каждый символ «-5», «-3», «0», «3», «5» помещался в ArrayList отдельно.

            ratings2DArray.get(counter).add(Integer.parseInt(rating));
            counter ++;
        }

        in.close();

    } catch (IOException e) {
        System.out.println(e.getMessage());
    }

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


person Marcos    schedule 22.01.2012    source источник


Ответы (2)


Вы движетесь в правильном направлении. Не забывайте всегда организовывать свой код в логические единицы, это помогает в процессе концептуализации и обслуживании вашей программы в будущем.

public List<List<Integer>> parseRatingsFile(String fileName) throws IOException {
    List<List<Integer>> ratings2DArray = new ArrayList<List<Integer>>(16);

    final BufferedReader in = new BufferedReader(new FileReader(fileName));
    String ratingsLine = null;
    while ((ratingsLine = in.readLine()) != null) {
        ratings2DArray.add(parseRatingsLine(ratingsLine));
    }
    in.close();

    return ratings2DArray;
}

public List<Integer> parseRatingsLine(String ratingsLine) IOException {
    List<Integer> ratings = new ArrayList<Integer>(8);
    if(ratingsLine == null) return ratings;

    String[] ratingsStrArr = ratingsLine.split(" "); // Tokenize on 'space' character
    for(final String ratingStr: ratingsStrArr) {
        // Here you would parse the ratingStr as an Integer, and
        // add it to your list
    }

    return ratings;
}

Вы должны обрабатывать исключения NumberFormatException, которые могут возникнуть при разборе отдельных целых чисел. Вы заметите, что я удалил переменную counter, она усложняет вашу программу и может быть источником ошибок. Удачи с остальными домашними заданиями.

person Perception    schedule 22.01.2012
comment
Вау, это большая помощь. Спасибо. Не возражаете, если я задам вам несколько вопросов об этом, чтобы лучше понять код? - person Marcos; 23.01.2012
comment
Конечно, что вам нужно помочь понять? - person Perception; 23.01.2012
comment
Что означают 16 и 8 внутри метода ArrayList? List‹List‹Integer›› ratings2DArray = new ArrayList‹List‹Integer››(16); Кроме того, правильно ли я думаю, что цикл while добавляет строки после того, как столбцы были созданы по отдельности в методе parseRatingsLine? - person Marcos; 23.01.2012
comment
Класс ArrayList определяет конструктор, который принимает int в качестве параметра. Параметр int определяет начальную емкость списка, в приведенном выше примере кода до 16 и 8 соответственно. Вы можете заменить 16 и 8 значениями, более подходящими для вашего варианта использования — емкость первого списка массивов должна приблизительно соответствовать количеству ожидаемых строк оценок в файле. Размер второго списка массивов должен приблизительно соответствовать количеству ожидаемых оценок в строке. - person Perception; 23.01.2012
comment
Да, цикл while вызывает метод parseRatingsLine(...) и добавляет его результат в список ratings2DArray. - person Perception; 23.01.2012
comment
И что сделано для повышения эффективности? Что, если эти цифры могут измениться? - person Marcos; 23.01.2012
comment
Вы можете сохранить эти числа в переменных и установить их в соответствии с параметрами вашей программы. - person Perception; 23.01.2012
comment
Я был в этом весь день (это всего лишь небольшая часть проекта и дополнительная заслуга в том, как я это делаю), что теперь мой мозг превратился в кашу, и я не могу понять, что будет дальше. внутри расширенного цикла for (на самом деле я не имел с ним дело в школе, только обычный цикл for). Не могли бы вы помочь мне с этим последним? я деф. принимая ваш ответ. myGratitude = (Спасибо) * (100). - person Marcos; 23.01.2012
comment
Вы анализируете ratingStr как целое число и добавляете его в коллекцию ratings. Что-то вроде ratings.add(Integer.valuesOf(ratingStr));. Вам придется обработать возможное исключение NumberFormatException — я рекомендую повторно создать его как исключение IOException. - person Perception; 23.01.2012
comment
Я написал что-то подобное (Integer.parseInt() вместо Integer.valueOf()), но я застрял, потому что не знаю, что представляет ratingStr в расширенном цикле for... И для исключения... попытка поймать блок работает? - person Marcos; 23.01.2012
comment
Integer.parseInt и Integer.valueOf почти идентичны, за исключением того, что последний возвращает объект Integer напрямую, а другой возвращает примитив int, который автоматически упаковывается для вас в объект Integer. Используйте все, что плавает на вашей лодке. И да, блок try-catch — это то, что вы использовали бы для обработки исключения. - person Perception; 23.01.2012

  • Это возможно с подходом, который вы следуете
  • Что касается дизайна структуры данных, попробуйте использовать List interface, например:

    List<List<Integer>> ratings2DArray = new ArrayList<ArrayList<Integer>>();

    Причина этого в том, что теперь завтра вы можете изменить ArrayList на что-то другое.

  • Что касается эффективности, ваш soln довольно эффективен в отношении характера ваших потребностей. Если кому-то действительно нужно выжимать больше производительности, код может быть не таким читабельным. Я думаю, одно решение для производительности (на моей голове), при условии, что нет. столбцов являются постоянными для всего файла, нужно избавиться от второго/вложенного ArrayList и заменить его массивом фиксированного размера int.

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


Разработка решения по оптимизации на основе приведенного ниже комментария.

Итак, вы говорите, что столбец представляет книгу (каждый столбец - это отдельная книга), а строки представляют клиента (каждая строка - другой клиент)...

Скажем, я выбираю -100 в качестве значения для книг без рейтинга (для ясности в данных есть лишние пробелы).

           Book1 Book2 Book3 Book4
Customer1  -100   5      5      3
Customer2    0    3      2    -100

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

Скажем, добавлена ​​книга «Book5».

           Book1 Book2 Book3 Book4 Book5
Customer1  -100   5      5      3   -100
Customer2    0    3      2    -100  -100

Скажем, клиент «Клиент3» добавлен.

           Book1 Book2 Book3 Book4 
Customer1  -100   5      5      3 
Customer2    0    3      2    -100
Customer3  -100  -100  -100   -100

Таким образом, в обоих случаях чтение первой строки говорит нам, что нет. столбцов, и они остаются постоянными для файла.


Теперь, если вы хотите добавить что-то в память List, то приведенное выше решение не очень оптимизировано. При каждом обновлении придется изменять размер массива. Оптимизации обычно предназначены для конкретных случаев использования.

Так что для добавления данных в память я думаю, что ваш текущий раствор подойдет. Единственное, что вы можете сделать, это передать количество столбцов в создание ArrayList, например:

// We are telling ArrayList the expected data size
// You can choose noOfColumns + some value according to ur need
// It will expand if more is needed
ratings2DArray.add(new ArrayList<Integer>(noOfColumns));

при загрузке файла. Таким образом, ArrayList будет кратким и улучшит производительность.

person havexz    schedule 22.01.2012
comment
Я не думаю, что смогу иметь строки или столбцы в виде фиксированной суммы. Я работаю над проектом рейтинга книг, и каждая строка (строка) представляет рейтинги, данные покупателем, а столбцы - рейтинги для любой данной книги. Поскольку я должен иметь возможность свободно добавлять клиентов и книги, лучшим решением, которое я мог придумать, было бы использование полностью динамического 2D ArrayList. Спасибо хоть. - person Marcos; 23.01.2012
comment
@Marcos добавил еще кое-что к вашему комментарию. - person havexz; 23.01.2012
comment
Спасибо, да, я сделал отдельный массив для названий книг и, вероятно, создам переменную int, используя метод size этого массиваList, чтобы передать количество столбцов в этот массивList. - person Marcos; 23.01.2012