Read specific columns from a file in Java 8 using streams, and put them in a 2D array

Wassim Alsafwi :

I have an input file that looks like this

@id1   1.2   3.4
@id2   6.8   8.1
@id3   1.5   9.4
@id4   5.9   2.7

I would like to store the numbers only in a 2D array, and forget about the 1st column that contains the @id. I also want to use streams only for that operation.

So far I made 2 methods :

First method read the input file and store each lines in a List, as an array of string :

private List<String[]> savefromfile(String filePath) throws IOException {

        List<String[]> rowsOfFile = new LinkedList<String[]>();
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.forEach(line -> {
                String rows[] = line.trim().split("\\s+");
                rowsOfFile.add(rows);
            });
            lines.close();
        }
        return rowsOfFile;

The second method take as an input the List, and return a 2D Array that contains only the columns numbers :

private double[][] storeAllID(List<String[]> rowsOfFile) {
        int numberOfID = rowsOfFile.size();
        double[][] allID = new double[numberOfID][2];
        int i = 0;
        for (String[] line : rowsOfFile) {
            double id[] = new double[2];
            id[0] = Double.parseDouble(line[1]); 
            id[1] = Double.parseDouble(line[2]);
            allID[i++] = id;
        }
        return allID;
    }

Is there a way to make this code more efficient ? I want only one, short method that read the input file and return a 2D array containing numbers only. I don't think it's necessary to write 20 lines of code to do this.

vlumi :

You aren't really gaining any benefit on your use of a stream in savefromfile, since you are using it exactly like it was a plain for-loop. To make the code a bit cleaner, you could get rid of the local variable completely, and also the call to close() is unnecessary as you are using try-with-resources already.

private List<String[]> savefromfile(String filePath) throws IOException {
    try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
        return lines
            .map(line -> line.trim().split("\\s+"))
            .collect(Collectors.toCollection(LinkedList::new));
    }
}

I don't know why you want to separate the parsing to double[][] into a separate method, as you could do it within your stream with a map:

    private double[][] loadFromFile(String filePath) throws IOException {
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            return lines
                .map(line -> line.trim().split("\\s+"))
                .map(line -> new double[] {
                    Double.parseDouble(line[1]),
                    Double.parseDouble(line[2])
                })
                .toArray(double[][]::new);
        }
    }

For performance, you'll just have to measure for yourself if using lower-level data types and loops would be worth the added complexity.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=123496&siteId=1