问题
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 as shown here in this example, [collect every 3 elements and print and so on...]
List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i","j");
int count=0;
String append="";
for(String l: list){
if(count>2){
System.out.println(append);
System.out.println("-------------------");
append="";
count=0;
}
append = append + l;
count++;
}
System.out.println(append);
output:
abc
-------------------
def
-------------------
ghi
-------------------
j
I am not getting any clue how to do this using stream. Should i implement my own collector to achieve this?
回答1:
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()))))
回答2:
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]
回答3:
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));
回答4:
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.
回答5:
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();
回答6:
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
来源:https://stackoverflow.com/questions/43057690/java-stream-collect-every-n-elements