Общий вопрос: как правильно реверсировать поток? Предполагая, что мы не знаем, из какого типа элементов состоит этот поток, каков общий способ реверсирования любого потока?
Конкретный вопрос:
IntStream
предоставляет метод диапазона для генерации целых чисел в определенном диапазоне IntStream.range(-range, 0)
, теперь, когда я хочу изменить его, диапазон переключения с 0 на отрицательный не будет работать, также я не могу использоватьInteger::compare
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);
с IntStream
я получу эту ошибку компилятора
Ошибка: (191, 0) ajc: метод
sorted()
в типеIntStream
не применим для аргументов (Integer::compare
)
что мне здесь не хватает?
IntStream
нет.sorted(Comparator)
метода; Вы должны пройтиStream<Integer>
сначала и повернуть туда, чтобы получитьIntStream
IntStream.range(0, n)
в обратном порядке, сделайте что-то вродеmap(i -> n - i - 1)
. Не нужно заниматься боксом и сортировкой.1, 3, 2
, каков, каков ваш ожидаемый результат? Вы хотите обратный поток, как2, 3, 1
или отсортированный поток, как3, 2, 1
?Ответы:
Для конкретного вопроса генерации реверса
IntStream
попробуйте что-то вроде этого:Это позволяет избежать упаковки и сортировки.
Что касается общего вопроса о том, как перевернуть поток любого типа, я не знаю, есть ли «правильный» способ. Есть несколько способов, о которых я могу думать. Оба заканчивают тем, что сохранили элементы потока. Я не знаю способа перевернуть поток без сохранения элементов.
Этот первый способ сохраняет элементы в массив и считывает их в поток в обратном порядке. Обратите внимание, что, поскольку мы не знаем тип времени выполнения элементов потока, мы не можем правильно набрать массив, что требует неконтролируемого приведения.
Другой метод использует коллекционеров для накопления предметов в обратном списке. Это делает много вставок перед
ArrayList
объектами, поэтому происходит много копий.Вероятно, можно написать гораздо более эффективный реверсивный коллектор, используя какую-то настроенную структуру данных.
ОБНОВЛЕНИЕ 2016-01-29
Поскольку этот вопрос в последнее время привлек немного внимания, я решил обновить свой ответ, чтобы решить проблему со вставкой в начале
ArrayList
. Это будет ужасно неэффективно с большим количеством элементов, требующих копирования O (N ^ 2).ArrayDeque
Вместо этого предпочтительнее использовать метод, который эффективно поддерживает вставку спереди. Небольшая морщина в том, что мы не можем использовать форму с тремя аргументамиStream.collect()
; для этого требуется, чтобы содержимое второго аргумента было объединено с первым аргументом, а массовая операция «добавить все впереди» не включенаDeque
. Вместо этого мы используемaddAll()
добавление содержимого первого аргумента к концу второго, а затем возвращаем второе. Это требует использованияCollector.of()
заводского метода.Полный код такой:
Результатом является «
Deque
вместо»List
, но это не должно быть большой проблемой, так как его можно легко повторять или передавать в обратном порядке.источник
IntStream.iterate(to-1, i->i-1).limit(to-from)
.limit(endExcl-(long)startIncl)
вместо этого, но для таких больших потоков, это в любом случае очень не рекомендуется, так как это гораздо менее эффективно, чемrange
решение на основе. На момент написания комментария я не знал о разнице в эффективности.Элегантное решение
источник
Comparable
...Многие из решений здесь сортируются или изменяются
IntStream
, но это излишне требует промежуточного хранения. Решение Стюарта Маркса - это путь:Он также правильно обрабатывает переполнение, пройдя этот тест:
источник
Estreams
имя (я собираюсь удалить его из поста). Это одна из внутренних служебных классов нашей компании, которые мы используем для дополненияjava.util.stream.Stream
«sstatic
метод.StreamEx
указав шаг:IntStreamEx.rangeClosed(from-1, to, -1)
Общий вопрос:
Stream не хранит никаких элементов.
Поэтому итерация элементов в обратном порядке невозможна без сохранения элементов в некоторой промежуточной коллекции.
Обновление: изменен LinkedList на ArrayDeque (лучше), смотрите здесь для деталей
Печать:
Между прочим, использование
sort
метода не является правильным, так как он сортирует, а НЕ переворачивает (при условии, что поток может иметь неупорядоченные элементы)Конкретный вопрос:
Я нашел это простым, легким и интуитивно понятным (Скопированный комментарий @Holger )
источник
sorted
иdistinct
фактически сохраняет промежуточный результат. Смотрите документацию по пакету API для получения дополнительной информации об этом.No storage
на той же странице. Даже в хранилищах мы не можем получить доступ к этому хранилищу (No storage
я думаю, это нормально)без внешней библиотеки ...
источник
В случае реализации
Comparable<T>
(напр.Integer
,String
,Date
), Вы можете сделать это с помощьюComparator.reverseOrder()
.источник
Stream.of(1,3,2)
результат,Stream.of(3,2,1)
НЕТStream.of(2,3,1)
Вы можете определить свой собственный сборщик, который собирает элементы в обратном порядке:
И используйте это как:
Я использую ArrayList в прямом порядке, чтобы эффективно вставлять коллекцию элементов (в конце списка), и Guava Lists.reverse, чтобы эффективно отображать список в обратном порядке, не делая еще одну его копию.
Вот несколько тестов для пользовательского сборщика:
источник
Циклоп -реакция StreamUtils имеет метод обратного потока ( Javadoc ).
Он работает, собирая в ArrayList, а затем используя класс ListIterator, который может выполнять итерацию в любом направлении, для итерации по списку.
Если у вас уже есть список, он будет более эффективным
источник
Я бы предложил использовать jOOλ , это отличная библиотека, которая добавляет множество полезных функций в потоки и лямбды Java 8.
Затем вы можете сделать следующее:
Просто как тот. Это довольно легкая библиотека, которую стоит добавить в любой проект Java 8.
источник
Вот решение, которое я придумала:
затем с помощью этих компараторов:
источник
Collections.reverseOrder()
существует с Java 1.2 и работает сInteger
…Как насчет этого вспомогательного метода?
Кажется, работает со всеми делами без дублирования.
источник
источник
Самый простой способ (простой сбор - поддерживает параллельные потоки):
Продвинутый способ (поддерживает параллельные потоки на постоянной основе):
Обратите внимание, что вы можете быстро распространяться на другие типы потоков (IntStream, ...).
Тестирование:
Полученные результаты:
Дополнительные примечания:
simplest way
это не так полезно при использовании с другими операциями потока (сборным присоединиться разбивает этот параллелизм). Этаadvance way
проблема не возникает, и, к примеруSORTED
, она также сохраняет начальные характеристики потока, и поэтому после обратного это способ использовать с другими операциями потока.источник
Можно написать коллектор, который собирает элементы в обратном порядке:
И используйте это так:
Оригинальный ответ (содержит ошибку - он не работает правильно для параллельных потоков):
Метод обратного потока общего назначения может выглядеть следующим образом:
источник
Не только Java8, но если вы используете метод Lists.reverse () в guava вместе, вы можете легко добиться этого:
источник
Что касается конкретного вопроса генерации реверса
IntStream
:начиная с Java 9 вы можете использовать версию с тремя аргументами
IntStream.iterate(...)
:где:
IntStream.iterate(int seed, IntPredicate hasNext, IntUnaryOperator next);
seed
- начальный элемент;hasNext
- предикат, применяемый к элементам, чтобы определить, когда поток должен завершиться;next
- функция, которая будет применена к предыдущему элементу для создания нового элемента.источник
Для справки я смотрел на ту же проблему, я хотел соединить строковое значение элементов потока в обратном порядке.
itemList = {последний, средний, первый} => первый, средний, последний
Я начал использовать промежуточную коллекцию
collectingAndThen
из комонады илиArrayDeque
собирателя Стюарта знаков , хотя я не был счастлив с промежуточной коллекцией, и снова потоковымПоэтому я перебрал ответ Стюарта Маркса, который использовал
Collector.of
фабрику, которая имеет интересную лямбду- финишер .Так как в этом случае поток не параллелен, объединитель не так уж важен, я все
insert
равно использую его для согласованности кода, но это не имеет значения, так как это будет зависеть от того, какой из сборщиков строк будет построен первым.Я посмотрел на StringJoiner, однако у него нет
insert
метода.источник
Отвечая на конкретный вопрос об обращении с IntStream, у меня сработало ниже:
источник
ArrayDeque
быстрее в стеке, чем Stack или LinkedList. «push ()» вставляет элементы в передней части Dequeисточник
Обратная строка или любой массив
разделение может быть изменено в зависимости от разделителя или пробела
источник
самое простое решение использует
List::listIterator
иStream::generate
источник
Stream.generate()
генерируется в бесконечном потоке, поэтомуlimit()
здесь очень важен вызов to .Вот как я это делаю.
Мне не нравится идея создания новой коллекции и ее повторения.
Идея карты IntStream # довольно изящна, но я предпочитаю метод итерации IntStream #, так как я думаю, что идея обратного отсчета до нуля лучше выражена с помощью метода итерации и ее легче понять с точки зрения перемещения массива назад-вперед.
Вот несколько тестов, чтобы доказать, что это работает:
источник
Во всем этом я не вижу ответа, на который я бы пошел первым.
Это не совсем прямой ответ на вопрос, но это потенциальное решение проблемы.
Просто создайте список задом наперед. Если вы можете, используйте LinkedList вместо ArrayList, а при добавлении элементов используйте «Push» вместо add. Список будет построен в обратном порядке и будет корректно передаваться без каких-либо манипуляций.
Это не подходит для случаев, когда вы имеете дело с примитивными массивами или списками, которые уже используются различными способами, но хорошо работают в удивительном количестве случаев.
источник
Этот метод работает с любым потоком и совместим с Java 8:
источник
Самый общий и самый простой способ отменить список будет:
источник
Comparator
. В результате никто не может гарантировать вам, что этот «трюк» будет работать в любой будущей версии Java с любым алгоритмом сортировки. Та же самая хитрость не работает, например, для параллельного потока, поскольку алгоритм параллельной сортировки используетComparator
по-другому. Для последовательной сортировки это работает чисто случайно. Я бы никому не рекомендовал использовать это решение.System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))
(хотя результат может зависеть от количества ядер).Java 8 способ сделать это:
источник