Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream a list of n-integers from a file to create n object array

Tags:

java

arrays

Assume each T object can be instantiated as

T tobj = new T(//int value);

So to create an array of T[ ] from integers in a file seperated by space I do the following:

 BufferedReader br;
 FileReader fr;
 int[] arr;
 try{               
        fr = new FileReader(fo); // assume "fo" file name
        br = new BufferedReader(fr);
        arr = Arrays.stream(br.readLine().split("\\s")).mapToInt(Integer::parseInt).toArray();

 }catch(SomeException e){//something else}

T[] tobjarr = new T[arr.length];
    for(int i=0; i<arr.length; ++i)){
        tobjarr[i] = new T(arr[i]);
    }

1.Is the above method efficient in terms of time and space usage?

2.Is there any other way? if so how does it compare to above method?

like image 400
magpie Avatar asked Mar 08 '23 08:03

magpie


2 Answers

In general your approach is fine. However, you can do that with a single stream cascade. Compared to your original approach this saves you one iteration.

Also note that nowadays we read files using Javas new I/O API called NIO. One big advantage is that it offers Stream methods. For example the Files#lines method that returns a stream over all lines of the file, perfectly suited for your approach.

So all in all, here is the complete code:

String file = ...
Pattern separator = Pattern.compile("\\s");

try (Stream<String> lines = Files.lines(Paths.get(file))) {
    T[] values = lines                      // Stream<String> lines
        .flatMap(separator::splitAsStream)  // Stream<String> words
        .mapToInt(Integer::parseInt)        // IntStream values
        .mapToObj(T::new)                   // Stream<T> valuesAsT
        .toArray(T[]::new);
} catch (IOException e) {
    System.out.println("Something went wrong.");
}

Note that this code is slightly different to yours, as yours will only process one line and mine all lines. You may change that if you don't want it:

List<T[]> valuesPerLine = Files.lines(Paths.get(file))  // Stream<String> lines
    .map(separator::splitAsStream)  // Stream<Stream<String>> wordsPerLine
    .map(lineStream -> {
        return lineStream                 // Stream<String> words
            .mapToInt(Integer::parseInt)  // IntStream values
            .mapToObj(T::new)             // Stream<T> valuesAsT
            .toArray(T[]::new);
    })                              // Stream<T[]> valuesPerLine
    .collect(Collectors.toList());

The main difference to your original approach is that we can easily transform an IntStream into a Stream<T> by using mapToObj(T::new) (or just map if it's a regular stream and not IntStream) which passes the elements to the constructor. After that we collect Stream<T> into an array by using toArray(T[]::new).

like image 148
Zabuzard Avatar answered Mar 09 '23 21:03

Zabuzard


T[] array = Arrays.stream(br.readLine().split("\\s"))
    .map(s -> new T(Integer.parseInt(s)))
    .toArray(T[]::new)

EDIT: noticed that you're using a different delimiter

like image 20
Alex Savitsky Avatar answered Mar 09 '23 23:03

Alex Savitsky