I have a question about lambda expressions. I have a class Pair which should hold a String and an int.
Pair gets the String out of a file. and the int is representiv for the line number. So far I have this:
Stream<String> lineNumbers = Files.lines(Paths.get(fileName));
List<Integer> posStream = Stream.iterate(0, x -> x + 1).limit(lineNumbers.count()).collect(Collectors.toList());
lineNumbers.close();
Stream<String> line = Files.lines(Paths.get(fileName));
List<Pair> pairs = line.map((f) -> new Pair<>(f,1))
.collect(Collectors.toList());
pairs.forEach(f -> System.out.println(f.toString()));
line.close();
How can I now input the file numbers to the pairs? Is there a lambda expression which can perform this? Or do I need something else?
There are a few ways to do this. The counter technique suggested by Saloparenator's answer could be implemented as follows, using an AtomicInteger
as the mutable counter object and assuming the obvious Pair
class:
List<Pair> getPairs1() throws IOException {
AtomicInteger counter = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(Paths.get(FILENAME))) {
return lines.parallel()
.map(line -> new Pair(line, counter.incrementAndGet()))
.collect(toList());
}
}
The problem is that if the stream is run in parallel, the counter won't be incremented in the same order as the lines are read! This will occur if your file has several thousand lines. The Files.lines
stream source will batch up bunches of lines and dispatch them to several threads, which will then number their batches in parallel, interleaving their calls to incrementAndGet()
. Thus, the lines won't be numbered sequentially. It will work if you can guarantee that your stream will never run in parallel, but it's often a bad idea to write streams that are likely to return different results sequentially vs. in parallel.
Here's another approach. Since you're reading all the lines into memory no matter what, just read them all into a list. Then use a stream to number them:
static List<Pair> getPairs2() throws IOException {
List<String> lines = Files.readAllLines(Paths.get(FILENAME));
return IntStream.range(0, lines.size())
.parallel()
.mapToObj(i -> new Pair(lines.get(i), i+1))
.collect(toList());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With