Tác vụ bạn muốn đạt được hoàn toàn khác với những gì nhóm làm. groupingBy
không phụ thuộc vào thứ tự của các thành phần của Stream
nhưng trên thuật toán của Map
được áp dụng cho kết quả phân loại Function
.
Điều bạn muốn là xếp các mục liền kề có giá trị thuộc tính chung vào một mục List
. Thậm chí không cần thiết phải có số Stream
được sắp xếp theo thuộc tính đó miễn là bạn có thể bảo đảm rằng tất cả các mục có cùng giá trị thuộc tính được nhóm lại.
Có thể bạn có thể xây dựng nhiệm vụ này như một sự giảm nhưng đối với tôi cấu trúc kết quả trông quá phức tạp.
Vì vậy, trừ khi hỗ trợ trực tiếp cho tính năng này được thêm vào Stream
s, một cách tiếp cận lặp dựa trông thực dụng nhất đối với tôi:
class Folding<T,G> implements Spliterator<Map.Entry<G,List<T>>> {
static <T,G> Stream<Map.Entry<G,List<T>>> foldBy(
Stream<? extends T> s, Function<? super T, ? extends G> f) {
return StreamSupport.stream(new Folding<>(s.spliterator(), f), false);
}
private final Spliterator<? extends T> source;
private final Function<? super T, ? extends G> pf;
private final Consumer<T> c=this::addItem;
private List<T> pending, result;
private G pendingGroup, resultGroup;
Folding(Spliterator<? extends T> s, Function<? super T, ? extends G> f) {
source=s;
pf=f;
}
private void addItem(T item) {
G group=pf.apply(item);
if(pending==null) pending=new ArrayList<>();
else if(!pending.isEmpty()) {
if(!Objects.equals(group, pendingGroup)) {
if(pending.size()==1)
result=Collections.singletonList(pending.remove(0));
else {
result=pending;
pending=new ArrayList<>();
}
resultGroup=pendingGroup;
}
}
pendingGroup=group;
pending.add(item);
}
public boolean tryAdvance(Consumer<? super Map.Entry<G, List<T>>> action) {
while(source.tryAdvance(c)) {
if(result!=null) {
action.accept(entry(resultGroup, result));
result=null;
return true;
}
}
if(pending!=null) {
action.accept(entry(pendingGroup, pending));
pending=null;
return true;
}
return false;
}
private Map.Entry<G,List<T>> entry(G g, List<T> l) {
return new AbstractMap.SimpleImmutableEntry<>(g, l);
}
public int characteristics() { return 0; }
public long estimateSize() { return Long.MAX_VALUE; }
public Spliterator<Map.Entry<G, List<T>>> trySplit() { return null; }
}
Bản chất lười biếng của kết quả gấp Stream
thể được chứng minh tốt nhất bằng cách áp dụng nó đến một dòng vô hạn:
Folding.foldBy(Stream.iterate(0, i->i+1), i->i>>4)
.filter(e -> e.getKey()>5)
.findFirst().ifPresent(e -> System.out.println(e.getValue()));
thế nào có thể bạn lười biếng nhóm theo? Để nhóm theo một số thuộc tính của đối tượng có trong Luồng, bạn phải lặp qua tất cả các phần tử trong Luồng. – Eran
Bạn có ý gì khi "nhóm các dòng của nó?" bạn có nghĩa là binning như phương pháp Stream 'groupBy' hoặc bạn có nghĩa là đọc nhiều dòng tại một thời điểm với số lượng lớn? – dkatzel
Cảm ơn nhận xét, đã thêm CẬP NHẬT vào câu hỏi. –