0

I am trying to read a text file into an ArrayList<ArrayList<String>>

The File Looks like:

A D E F
B A F
C A B D
D B C
E B C D F
F A B D
G
H A D F

Following is my piece of code:

private static void registerPages() throws IOException {
        Scanner input = new Scanner(new File(webPath));
        //input.useDelimiter(" ");


        ArrayList<ArrayList<String>> arrayList = new ArrayList<>();
        ArrayList<String> row = new ArrayList<>();
        String tempStr;
        String[] tempArr;

        while (input.hasNextLine())
        {
            row.clear();
            tempStr = input.nextLine(); //get row in string
            tempArr = tempStr.split(" "); //split string into strings[]
            Collections.addAll(row, tempArr); //add each strings[] to arrayList
            arrayList.add(row); //add arrayList to arrayList
        }

        System.out.println("arrayList:\n" + arrayList);

    }

The output is:

arrayList:
[[H, A, D, F], [H, A, D, F], [H, A, D, F], [H, A, D, F], [H, A, D, F], [H, A, D, F], [H, A, D, F], [H, A, D, F]]

The wanted output is:

arrayList:
[[A, D, E, F], [B, A, F], [C, A, B, D], [D, B, C], [E, B, C, D, F], [F, A, B, D], [G], [H, A, D, F]]

Just FYI, this text file is supposed to be a webgraph. First word is a web-page. Next words in the same line are other webpages linking to this web-page (in-links). Eventually, i am supposed to code the 'Page Rank' algorithm.

Thank You in advance.

Abdul Wasae
  • 3,614
  • 4
  • 34
  • 56
  • The error has nothing directly to do with reading the input. It is rooted in how objects and references are used in Java. Your problem is that it is always the latest row yes? The reason for it is that `Collections.addAll(row, tempArr); //add each strings[] to arrayList` overrides all previous ones. – Emz Nov 17 '15 at 17:09
  • Yes. Debugging it indicated so. But i still don't understand why it does so – Abdul Wasae Nov 17 '15 at 17:18

5 Answers5

2

Instead of using row.clear() try instantiate row in each iterations. row = new ArrayList<>()

Hint:
You are creating row only once. So all item holders in arrayList points to the same memory block. You have to create new instances (Real object in memory) so they can hold different values.

  • First of all, Thank you. It worked. However, i'd really like to know, why! when i arrayList.add(), is it not 'Deep Copying' the data? – Abdul Wasae Nov 17 '15 at 17:19
  • Oh My God! that was silly of me. I get it now!. Thank you so very much for the much appreciated explanation along with the fix. – Abdul Wasae Nov 17 '15 at 17:21
1
public static void main(String[] args) {
    File file = new File("webpath.txt"); // Your text file
    ArrayList<List<String>> arrayList = new ArrayList<>();

    try(Scanner sc = new Scanner(file)) {
        List<String> arrayRow = new ArrayList<>();

        while (sc.hasNextLine()) {
            String line = sc.nextLine(); // Retrieve 1 line from the text file
            String[] data = line.split(" "); // Splitting the characters and storing them
            arrayRow = Arrays.asList(data); // Converting array to List
            arrayList.add(arrayRow); // Adding row of characters to the final arraylist
        }
    }
    catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    // Looping through the result arraylist
    for (List<String> array : arrayList) {
        for(String item : array) {
            System.out.print(item + " ");
        }
        System.out.println();
    }
}
Mohammed Aouf Zouag
  • 17,042
  • 4
  • 41
  • 67
  • 1
    We should close resources in `finally` block to ensure that `sc.close();` will be called regardless if exception will be thrown or not. Or better yet use try-with-resources which can handle that for us. – Pshemo Nov 17 '15 at 17:18
1

Problem is that you are reusing and adding to arrayList same instance of list representing row (so it prints N times current/last state). You should create new list for each row and then add it to your main list.

So simply move ArrayList<String> row = new ArrayList<>(); inside your loop and.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
0

You add the same row many times in the arrayList. Every time you modify the same row and finally you have only the last row inserted many time. You have to create new row every time: put line ArrayList row = new ArrayList<>(); in place of row.clear();

0
public static void main(String[] args) throws IOException {
    registerPages(new FileReader("test.txt"));
}

private static void registerPages(Reader reader) throws IOException {
    Scanner input = new Scanner(reader);
    List<List<String>> arrayList = new ArrayList<>();

    while (input.hasNextLine()) {
        List<String> row = new ArrayList<>();
        Collections.addAll(row, input.nextLine().split(" "));
        arrayList.add(row);
    }

    System.out.println("arrayList:\n" + arrayList);
}

Outputs:

arrayList:
[[A, D, E, F], [B, A, F], [C, A, B, D], [D, B, C], [E, B, C, D, F], [F, A, B, D], [G], [H, A, D, F]]

The problem with your code was that you were constantly operating on the same row instance. The main arrayList instance had the same instance of a List in it multiple times, and you were constantly re-adding the same instance, clearing and setting new data for it every time. That's why you are seeing the same result on all entries for arrayList - it basically contains the same list multiple times. This is because the list is a mutable object - It's state can be modified and by passing it to another data structure does not prevent it from reflecting the changes made to it in the other data structure. By passing an object (e.g. to another method) does not mean you are copying its contents, you are sharing that object with the other method. Both are seeing the same object - and changes to the shared object are visible to both.

randers
  • 5,031
  • 5
  • 37
  • 64