0

I have a .txt file that contains text that I would like to save part of it in a String, part of it in a String array, and then the last part in a 2D int array, and am faced with two issues:

  1. How to read and save both of the arrays when their size is not known ahead of time?
  2. 2D array is not reading/saving properly

Here is the text file for reference:

This is the sentence to be read.
This
is
a
String
array.
90 47 110 95 95
101 87 
54 0 38 12 

Here is part of my method that is supposed to read and save the three data types:

BufferedReader br = new BufferedReader(new FileReader(fileName));
        
        sentence = br.readLine();

        stringArr = new String[5]; //how to initialize without set number of elements?
        for(int i = 0; i<stringArr.length; i++){
            stringArr[i] = br.readLine();
        }

        int2DArr = new int[3][5]; //how to initialize with any amount of rows and columns?
        for(int i = 0; i<int2DArr.length; i++){
            for(int j = 0; j<int2DArr[i].length; j++){
                int2DArr[i][j] = br.read();
                //how to read the space after each int ?
            }
        }

How would I "grab" the size of the arrays by reading the text file, so that when I initialize both arrays, I have the proper sizes? Any help would be greatly appreciated!

  • I think you should use a `while` loop to iterate through the lines of text. Look at the many examples on the web on how to read a file in Java. You can always initialize an `int` outside the loop to capture the line index and you can increment said variable by one inside the `while`. – hfontanez Dec 31 '21 at 21:54
  • @hfontanez, right, but then how would I know when I've reached the 2d int array and to switch data types? – user17762591 Dec 31 '21 at 21:56
  • That's why clear requirements help. None of us know anything about this file structure. Are all files ALWAYS going to have the same number of lines and the same arrangement of data? Why is one file used to store mixed data types? Seems to me, they should be stored in separate files. – hfontanez Dec 31 '21 at 21:59
  • Also, you can always store numbers as strings and convert to numbers later. – hfontanez Dec 31 '21 at 22:00
  • @hfontanez file structure must be a String, followed by a String array, followed by a 2D int array, as shown above. The files will always have the same arrangement of data, just not the same array size – user17762591 Dec 31 '21 at 22:02
  • The problem in my opinion is that you are trying to do everything in a single method. You have at least two problems that need solving: 1) Read the file to extract file contents, and 2) Determine the data type of each read line. That would be my approach. This is how you solve problems in the real world. This process is called "Problem Decomposition". – hfontanez Dec 31 '21 at 22:10

2 Answers2

1

Instead of trying to achieve everything in a single pass we can pass through the file twice and obtain a neater code.

It will consume double time of course but it is going to help you understand how you could break bigger problems into smaller ones and deal with them one by one.

Here are the steps:

  1. Determine size of stringArr and intArr in first pass
  2. Fill value in respective array in second pass

If you are wondering how no of columns for int2DArr is determine. Simply we don't do it our self. We use the concept of Jagged Arrays

Read more here How do I create a jagged 2d array in Java?

import java.util.*;
import java.io.*;

class ReadFileIntoArr {
    public static void main(String args[]) throws IOException {
        String fileName = "test.txt";
        BufferedReader br = new BufferedReader(new FileReader(fileName));

        String line = br.readLine();
        int strSize = 0;
        int intSize = 0;
        boolean isDigit = false;

        while (line != null && line.trim().length() != 0) {
            if (!isDigit && Character.isDigit(line.charAt(0)))
                isDigit = true;
            if (isDigit)
                intSize++;
            else
                strSize++;
            line = br.readLine();
        }

        br = new BufferedReader(new FileReader(fileName));

        String[] stringArr = new String[strSize];
        for (int i = 0; i < stringArr.length; i++)
            stringArr[i] = br.readLine();

        int[][] int2DArr = new int[intSize][];
        for (int i = 0; i < int2DArr.length; i++)
            int2DArr[i] = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();

        System.out.println(Arrays.toString(stringArr));
        System.out.println(Arrays.deepToString(int2DArr));
    }
}

Note: In single pass this could be accomplished with the help of ArrayList and later transfer everything into respective array.

Update: After understanding the constraints for your problem here is another version

import java.util.*;
import java.io.*;

class ReadFileIntoArr {
    public static void main(String args[]) throws IOException {
        String fileName = "test.txt";
        BufferedReader br = new BufferedReader(new FileReader(fileName));

        String line = br.readLine();
        int strSize = 0;
        int intSize = 0;
        boolean isDigit = false;

        while (line != null && line.trim().length() != 0) {
            if (!isDigit && isDigit(line.charAt(0)))
                isDigit = true;
            if (isDigit)
                intSize++;
            else
                strSize++;
            line = br.readLine();
        }

        br = new BufferedReader(new FileReader(fileName));

        String[] stringArr = new String[strSize];
        for (int i = 0; i < stringArr.length; i++)
            stringArr[i] = br.readLine();

        int[][] int2DArr = new int[intSize][];
        for (int i = 0; i < int2DArr.length; i++)
            int2DArr[i] = convertStringArrToIntArr(br.readLine().split(" "));

        System.out.println(Arrays.toString(stringArr));
        System.out.println(Arrays.deepToString(int2DArr));
    }

    public static boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }

    public static int[] convertStringArrToIntArr(String[] strArr) {
        int[] intArr = new int[strArr.length];
        for (int i = 0; i < strArr.length; i++)
            intArr[i] = Integer.parseInt(strArr[i]);
        return intArr;
    }
}
Lovesh Dongre
  • 1,294
  • 8
  • 23
  • Thanks for taking the time to explain this! I knew I had to go through it twice as you mentioned, just was not sure about how that would look like. However, I don't think I can use .stream or .mapToInt due to the restrictions of my assignment, what exactly do those methods do? I also think I have to manually write an .isDigit() method, that just checks if the current char is a number right? – user17762591 Dec 31 '21 at 23:49
  • `.stream` is used to create a stream from Array in this case and .mapToInt can be used on a stream to convert stream datatype into int (primitive datatype). I have updated a second version of the code with isDigit and a way to avoid using stream and mapToInt. – Lovesh Dongre Jan 01 '22 at 12:05
0
Path path = Paths.get(fileName);
List<String> lines = Files.readAllLines(path, Charset.defaultCharset());

String title = lines.get(0);
List<String> words = new ArrayList<>();
for (int i = 1; i < lines.size(); ++i) {
    String word = lines.get(i);
    if (!word.isEmpty() && Character.isDigit(word.codePointAt(0)) {
        break;
    }
    words.add(word);
}
String[] wordArray = words.toArray(new String[]);
int i0 = 1 + words.size();
int n = lines.size() - i0;
int[][] numbers = new int[n][];
for (int i = i0; i < lines.size(); ++i) {
    String[] values = lines.get(i).trim().split("\\s+");
    int m = values.length;
    int[] row = new int[m];
    for (int j = 0; j < m; ++m) {
        row[j] = Integer.parse(values[j]);
    }
    numbers[i - i0] = row;
}
  • Path is a generalisation of File, also URLs.
  • Files is a treasure trove of file functions.
  • One could do without dynamically sized List; one would need to test first, but normally one would use a List anyhow.
  • String.split splits on one or more whitespace.
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138