Для конкретного вопроса генерации реверса IntStream
попробуйте что-то вроде этого:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Это позволяет избежать упаковки и сортировки.
Что касается общего вопроса о том, как перевернуть поток любого типа, я не знаю, есть ли «правильный» способ. Есть несколько способов, о которых я могу думать. Оба заканчивают тем, что сохранили элементы потока. Я не знаю способа перевернуть поток без сохранения элементов.
Этот первый способ сохраняет элементы в массив и считывает их в поток в обратном порядке. Обратите внимание, что, поскольку мы не знаем тип времени выполнения элементов потока, мы не можем правильно набрать массив, что требует неконтролируемого приведения.
@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]);
}
Другой метод использует коллекционеров для накопления предметов в обратном списке. Это делает много вставок перед ArrayList
объектами, поэтому происходит много копий.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Вероятно, можно написать гораздо более эффективный реверсивный коллектор, используя какую-то настроенную структуру данных.
ОБНОВЛЕНИЕ 2016-01-29
Поскольку этот вопрос в последнее время привлек немного внимания, я решил обновить свой ответ, чтобы решить проблему со вставкой в начале ArrayList
. Это будет ужасно неэффективно с большим количеством элементов, требующих копирования O (N ^ 2).
ArrayDeque
Вместо этого предпочтительнее использовать метод, который эффективно поддерживает вставку спереди. Небольшая морщина в том, что мы не можем использовать форму с тремя аргументами Stream.collect()
; для этого требуется, чтобы содержимое второго аргумента было объединено с первым аргументом, а массовая операция «добавить все впереди» не включена Deque
. Вместо этого мы используем addAll()
добавление содержимого первого аргумента к концу второго, а затем возвращаем второе. Это требует использования Collector.of()
заводского метода.
Полный код такой:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
Результатом является « Deque
вместо» List
, но это не должно быть большой проблемой, так как его можно легко повторять или передавать в обратном порядке.
IntStream
нет.sorted(Comparator)
метода; Вы должны пройтиStream<Integer>
сначала и повернуть туда, чтобы получитьIntStream