I am trying to learn java - stream. I am able to do simple iteration / filter / map / collection etc.
When I was kind of trying to collect every 3 elements and print
You can actually use an IntStream
to simulate your list's pagination.
List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
int pageSize = 3;
IntStream.range(0, (list.size() + pageSize - 1) / pageSize)
.mapToObj(i -> list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size())))
.forEach(System.out::println);
which outputs:
[a, b, c]
[d, e, f]
[g, h, i]
[j]
If you want to generate Strings, you can use String.join
since you are dealing with a List<String>
directly:
.mapToObj(i -> String.join("", list.subList(i * pageSize, Math.min(pageSize * (i + 1), list.size()))))
The most obvious solution:
IntStream.range(0, list.size() / N)
.map(i -> i * charactersAmount)
.mapToObj(i -> list.subList(i, i + charactersAmount)
.collect(Collectors.toWhateverYouWant());
The first line - you will get a stream of ints from 0 to amount of resulting lines. From your example, list.size() / N equals 4, so stream will be 0-1-2-3.
The second line - this stream will be mapped to the scaled by the charactersAmount one, in your case it is 3 - 0-3-6-9.
The third line will cut sublists out of your initial list.
The last line just treats the resulting stream as collection
You can create your own Collector
. The easiest way is to call Collector.of().
Since your use case requires values to be processed in order, here is an implementation that simply doesn't support parallel processing.
public static Collector<String, List<List<String>>, List<List<String>>> blockCollector(int blockSize) {
return Collector.of(
ArrayList<List<String>>::new,
(list, value) -> {
List<String> block = (list.isEmpty() ? null : list.get(list.size() - 1));
if (block == null || block.size() == blockSize)
list.add(block = new ArrayList<>(blockSize));
block.add(value);
},
(r1, r2) -> { throw new UnsupportedOperationException("Parallel processing not supported"); }
);
}
Test
List<String> input = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
List<List<String>> output = input.stream().collect(blockCollector(3));
output.forEach(System.out::println);
Output
[a, b, c]
[d, e, f]
[g, h, i]
[j]
If you have Guava in your project, you can use Iterables.partition
method:
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
...
Stream<List<String>> stream = Streams.stream(Iterables.partition(list, 3));
I solved it like this:
List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
int groupBy = 3;
AtomicInteger index = new AtomicInteger(0);
Map<Integer, List<String>> groups = list.stream()
.collect(Collectors.groupingBy(cdm -> index.getAndIncrement()/groupBy));
System.out.println(groups);
It prepares a map where the line number is the key and the strings on the line are in the key.
I think the bets approach is using an amazing library StreamEx of Tagir Valeev. The solution fits in one line ))
StreamEx.ofSubLists(list, 3).toList();