Đối với câu hỏi cụ thể về việc tạo đảo ngược IntStream
, hãy thử một cái gì đó như thế này:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Điều này tránh đấm bốc và phân loại.
Đối với câu hỏi chung về cách đảo ngược bất kỳ loại nào, tôi không biết có cách nào "phù hợp". Có một vài cách tôi có thể nghĩ ra. Cả hai cuối cùng lưu trữ các yếu tố dòng. Tôi không biết cách đảo ngược luồng mà không lưu trữ các phần tử.
Cách đầu tiên này lưu trữ các phần tử thành một mảng và đọc chúng ra một luồng theo thứ tự ngược lại. Lưu ý rằng vì chúng tôi không biết loại thời gian chạy của các thành phần luồng, chúng tôi không thể nhập đúng mảng, yêu cầu bỏ chọn không được kiểm tra.
@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
Object[] temp = input.toArray();
return (Stream<T>) IntStream.range(0, temp.length)
.mapToObj(i -> temp[temp.length - i - 1]);
}
Một kỹ thuật khác sử dụng các bộ sưu tập để tích lũy các mục vào một danh sách đảo ngược. Điều này không có nhiều phần chèn vào phía trước các ArrayList
đối tượng, vì vậy có rất nhiều sự sao chép đang diễn ra.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Có lẽ có thể viết một trình thu thập đảo ngược hiệu quả hơn bằng cách sử dụng một số loại cấu trúc dữ liệu tùy chỉnh.
CẬP NHẬT 2016-01-29
Vì câu hỏi này đã nhận được một chút chú ý gần đây, tôi cho rằng tôi nên cập nhật câu trả lời của mình để giải quyết vấn đề bằng cách chèn ở phía trước ArrayList
. Điều này sẽ không hiệu quả khủng khiếp với một số lượng lớn các yếu tố, yêu cầu sao chép O (N ^ 2).
Tốt nhất là sử dụng ArrayDeque
thay thế, hỗ trợ hiệu quả việc chèn ở phía trước. Một nếp nhăn nhỏ là chúng ta không thể sử dụng hình thức ba đối số Stream.collect()
; nó yêu cầu nội dung của đối số thứ hai được hợp nhất vào đối số thứ nhất và không có thao tác hàng loạt "bổ sung tất cả ở phía trước" Deque
. Thay vào đó, chúng tôi sử dụng addAll()
để nối các nội dung của đối số thứ nhất vào cuối giây thứ hai và sau đó chúng tôi trả lại nội dung thứ hai. Điều này đòi hỏi phải sử dụng Collector.of()
phương pháp nhà máy.
Mã hoàn chỉnh là đây:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Kết quả là Deque
thay vì một List
, nhưng điều đó không phải là vấn đề, vì nó có thể dễ dàng được lặp lại hoặc truyền phát theo thứ tự đảo ngược.
IntStream
không có.sorted(Comparator)
phương pháp; bạn phải trải quaStream<Integer>
lần đầu tiên và đảo ngược ở đó trước khi đạt được mộtIntStream