Как да попълня многомерен ArrayList (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.

Тук долу трябва да декларирам низ (или char?) променлива, наречена 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;
}

Трябва да обработвате NumberFormatExceptions, които могат да възникнат, докато анализирате отделни цели числа. Ще забележите, че изпуснах променливата 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 = нов 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 (на върха на главата ми), при предположението, че не. от колони са const за целия файл, е да се отървете от втория/вложен 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

Да кажем, че е добавен клиент „Customer3“.

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

И в двата случая прочитането на първия ред ни казва не. от колони и те остават const за файла.


Сега, ако искате да добавите нещо към паметта List, тогава горният soln не е много оптимизиран. Тъй като всяка актуализация ще трябва да промени размера на масива. Оптимизациите обикновено са за конкретни случаи на употреба.

Така че за добавяне на данни в паметта, мисля, че текущият ви soln ще се справи добре. Единственото, което можете да направите, е да предадете броя на колоните на 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 добави още нещо към ans относно вашия коментар. - person havexz; 23.01.2012
comment
Благодаря, да, направих отделен масив за заглавията на книгите и вероятно ще създам int променлива, използвайки метода size на този arrayList, за да предам броя колони на този arrayList. - person Marcos; 23.01.2012