Như Tagir Valeev lưu ý, loại vấn đề không được hỗ trợ tốt bởi API luồng. Nếu bạn từng muốn đọc các dòng từ đầu vào và in ra các dòng phù hợp với ngữ cảnh, bạn sẽ phải giới thiệu một giai đoạn đường ống trạng thái (hoặc một bộ sưu tập tùy chỉnh hoặc bộ tách) cho biết thêm một chút phức tạp.
Nếu bạn sẵn sàng đọc tất cả các dòng vào bộ nhớ, nó chỉ ra rằng BitSet
là một đại diện hữu ích cho thao tác nhóm các trận đấu. Điều này mang một số điểm tương đồng với giải pháp của Tagir, nhưng thay vì sử dụng dãy số nguyên để biểu diễn các dòng được in, nó sử dụng 1 bit trong một BitSet
. Một số ưu điểm của BitSet
là nó có một số hoạt động hàng loạt được tích hợp sẵn và nó có một biểu diễn bên trong nhỏ gọn. Nó cũng có thể tạo ra một luồng các chỉ mục của 1-bit, điều này khá hữu ích cho vấn đề này.
Đầu tiên, chúng ta hãy bắt đầu bằng cách tạo ra một BitSet
mà có một 1-bit cho mỗi dòng phù hợp với vị ngữ:
void contextMatch(Predicate<String> pred, int before, int after, List<String> input) {
int len = input.size();
BitSet matches = IntStream.range(0, len)
.filter(i -> pred.test(input.get(i)))
.collect(BitSet::new, BitSet::set, BitSet::or);
Bây giờ chúng ta có tập bit của dòng phù hợp, chúng tôi dòng ra các chỉ số của mỗi 1 bit. Sau đó chúng ta thiết lập các bit trong bitet đại diện cho bối cảnh trước và sau. Điều này cho chúng ta một số BitSet
có 1 bit đại diện cho tất cả các dòng được in, bao gồm các dòng ngữ cảnh.
BitSet context = matches.stream()
.collect(BitSet::new,
(bs,i) -> bs.set(Math.max(0, i - before), Math.min(i + after + 1, len)),
BitSet::or);
Nếu chúng ta chỉ muốn in ra tất cả các dòng, bao gồm bối cảnh, chúng ta có thể làm điều này:
context.stream()
.forEachOrdered(i -> System.out.println(input.get(i)));
Các thực tế grep -A a -B b
lệnh in một dấu phân cách giữa từng nhóm dòng ngữ cảnh. Để tìm ra khi in dấu phân cách, chúng ta xem xét từng bit 1 bit trong tập bit bối cảnh. Nếu có 0 bit trước nó, hoặc nếu nó ở ngay từ đầu, chúng tôi đã đặt một chút vào kết quả. Điều này cho chúng ta 1 bit ở đầu mỗi nhóm ngữ cảnh:
Chúng tôi không muốn in dấu phân cách trước mỗi nhóm dòng ngữ cảnh; chúng tôi muốn in nó giữa mỗi nhóm.Điều đó có nghĩa là chúng tôi phải xóa 1 bit đầu tiên (nếu có):
// clear the first bit
int first = separators.nextSetBit(0);
if (first >= 0) {
separators.clear(first);
}
Bây giờ, chúng tôi có thể in ra các dòng kết quả. Nhưng trước khi in mỗi dòng, chúng tôi kiểm tra để xem liệu chúng ta nên in một tách đầu tiên:
context.stream()
.forEachOrdered(i -> {
if (separators.get(i)) {
System.out.println("--");
}
System.out.println(input.get(i));
});
}
Đó là tiếc là không được hỗ trợ bởi các API Suối ra khỏi hộp, nhưng những gì bạn muốn được gọi là "trượt cửa sổ". –