Учитывая такой поток, как { 0, 1, 2, 3, 4 }
,
как мне наиболее элегантно преобразовать его в заданную форму:
{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }
(при условии, конечно, что я определил класс Pair)?
Изменить: это не совсем касается целых или примитивных потоков. Ответ должен быть общим для потока любого типа.
java
java-8
java-stream
Александр Дубинский
источник
источник
list.stream().map(i -> new Pair(i, i+1));
Map.Entry
как класс Pair. (Конечно, некоторые могут подумать, что это взлом, но использование встроенного класса удобно.)Ответы:
Моя библиотека StreamEx, которая расширяет стандартные потоки, предоставляет
pairMap
метод для всех типов потоков. Для примитивных потоков он не меняет тип потока, но может использоваться для выполнения некоторых вычислений. Чаще всего используется для вычисления различий:Для потока объектов вы можете создать любой другой тип объекта. Моя библиотека не предоставляет никаких новых видимых для пользователя структур данных вроде
Pair
(это часть концепции библиотеки). Однако, если у вас есть собственныйPair
класс и вы хотите его использовать, вы можете сделать следующее:Или, если у вас уже есть
Stream
:Эта функция реализована с помощью настраиваемого сплитератора . Он имеет довольно низкие накладные расходы и может хорошо распараллеливаться. Конечно, он работает с любым источником потока, а не только со списком / массивом произвольного доступа, как многие другие решения. Во многих тестах он показал себя очень хорошо. Вот тест JMH, где мы находим все входные значения, предшествующие большему значению, используя разные подходы (см. Этот вопрос).
источник
StreamEx
реализуетIterable
! Ура!)Stream
превратить a вStreamEx
?StreamEx.of(stream)
. Есть и другие удобные статические методы создания потока изCollection
, массиваReader
и т.д. Отредактировал ответ.pairMap
заказывается на последовательных потоках? На самом деле, я бы хотел иметь forPairsOrdered (), но, поскольку такого метода нет, могу ли я как-то его смоделировать?stream.ordered().forPairs()
илиstream().pairMap().forEachOrdered()
?pairMap
это промежуточная операция с невмешивающейся функцией сопоставления без сохранения состояния, для нее не указывается порядок так же, как для простойmap
.forPairs
Является неупорядоченной спецификацией, но неупорядоченные операции де-факто заказана для последовательных потоков. Было бы неплохо, если бы вы сформулировали свою исходную проблему как отдельный вопрос о стеке, чтобы предоставить больше контекста.Библиотека потоков Java 8 в первую очередь предназначена для разделения потоков на более мелкие фрагменты для параллельной обработки, поэтому этапы конвейера с сохранением состояния весьма ограничены, а выполнение таких действий, как получение индекса текущего элемента потока и доступ к смежным элементам потока, не поддерживается.
Типичный способ решения этих проблем с некоторыми ограничениями, конечно, состоит в том, чтобы управлять потоком с помощью индексов и полагаться на то, что значения обрабатываются в некоторой структуре данных с произвольным доступом, такой как ArrayList, из которой можно извлекать элементы. Если бы значения были внутри
arrayList
, можно было бы сгенерировать пары по запросу, выполнив что-то вроде этого:Конечно, ограничение состоит в том, что ввод не может быть бесконечным потоком. Однако этот конвейер можно запустить параллельно.
источник
arrayList
самом деле input ( ) - это коллекция, поэтому я не пометил ее как ответ. (Но поздравляю с золотым значком!)Это не изящно, это хакерское решение, но работает для бесконечных потоков
Теперь вы можете ограничить поток до желаемой длины.
PS Надеюсь, есть решение получше, что-то вроде clojure
(partition 2 1 stream)
источник
parallelStream
документу: «Чтобы сохранить правильное поведение, эти поведенческие параметры не должны мешать, и в большинстве случаев должны быть без гражданства»Я реализовал оболочку сплитератора, которая берет все
n
элементыT
из исходного сплитератора и производитList<T>
:Для создания последовательного потока можно использовать следующий метод:
Пример использования:
источник
List<E>
элементы. Каждый список содержитn
последовательные элементы из исходного потока. Проверьте это сами;)(partition size step)
Функция очень нужна, и это лучший способ ее получить.ArrayDeque
для повышения производительности, а неLinkedList
.Вы можете сделать это с помощью метода Stream.reduce () (я не видел других ответов, использующих эту технику).
источник
Вы можете сделать это в cyclops-react (я участвую в этой библиотеке), используя оператор скольжения.
Или
Предполагая, что конструктор Pair может принимать коллекцию с двумя элементами.
Если вы хотите сгруппировать по 4 и увеличить на 2, это также поддерживается.
Эквивалентные статические методы для создания скользящего представления для java.util.stream.Stream также предоставляются в классе циклоп-потоков StreamUtils .
Примечание: - для однопоточной работы больше подходит ReactiveSeq. LazyFutureStream расширяет ReactiveSeq, но в первую очередь предназначен для одновременного / параллельного использования (это Stream of Futures).
LazyFutureStream расширяет ReactiveSeq, который расширяет Seq из удивительного jOOλ (который расширяет java.util.stream.Stream), поэтому решения, представленные Лукасом, также будут работать с любым типом Stream. Для всех, кто интересуется, основные различия между операторами окна / скольжения заключаются в очевидном соотношении относительной мощности / сложности и пригодности для использования с бесконечными потоками (скольжение не потребляет поток, а буферизует его по мере его потока).
источник
Библиотека proton-pack обеспечивает оконную функциональность. Учитывая класс Pair и Stream, вы можете сделать это следующим образом:
Теперь
pairs
поток содержит:источник
st
дважды! Может ли эта библиотека решить проблему с помощью одного потока?windowed
Функционал добавлен! Смотрите редактирование.Поиск последовательных пар
Если вы хотите использовать стороннюю библиотеку и не нуждаетесь в параллелизме, тогда jOOλ предлагает оконные функции в стиле SQL следующим образом
Уступая
lead()
Функция получает доступ следующего значения в порядке обхода из окна.Нахождение последовательных троек / четверок / кортежей
Вопрос в комментариях просил о более общем решении, в котором должны собираться не пары, а n-кортежи (или, возможно, списки). Вот альтернативный подход:
Получение списка списков
Без него
filter(w -> w.count() == n)
результат был быОтказ от ответственности: я работаю в компании, стоящей за jOOλ
источник
w.lead().lead()
?tuple(w.value(), w.lead(1), w.lead(2))
был бы вариант. Я обновил свой ответ более общим решением дляlength = n
.window()
это не ленивая операция, которая собирает весь входной поток в какую-то промежуточную коллекцию, а затем создает из нее новый поток?Comparator
используется для изменения порядка окон), то оптимизация , как это было бы возможно, и, вероятно, будет реализован в будущем.Streams.zip(..)
доступен в Гуаве для тех, кто от него зависит.Пример:
источник
Мы можем использовать RxJava (очень мощная библиотека реактивных расширений )
источник
Observable.zip(obs, obs.skip(1), pair->{...})
до сих пор! Я не знал,Observable.buffer
что есть версия со ступенькой (и привык кzip
хитрости от python). +1Операция, по сути, имеет состояние, поэтому не совсем то, что потоки предназначены для решения - см. Раздел «Поведение без отслеживания состояния» в javadoc :
Одно из решений здесь - ввести состояние в ваш поток через внешний счетчик, хотя он будет работать только с последовательным потоком.
источник
Stream
:! = "Лямбды".StreamEx
Библиотека также хорошая находка , и может быть ответ сам по себе. Мой комментарий к «streams! = Lambdas» относится к тому, что вы заявляете: «Операция, по сути, с отслеживанием состояния, поэтому не совсем то, что лямбды предназначены для решения». Я думаю, вы хотели использовать слово «потоки».В вашем случае я бы написал свою собственную функцию IntFunction, которая отслеживает последний переданный int и использует его для сопоставления исходного IntStream.
источник
Для вычисления последовательных разностей во время (X-значение) из временных рядов, я использую
stream
«ыcollect(...)
метода:Где DifferenceCollector выглядит примерно так:
Возможно, вы могли бы изменить это в соответствии со своими потребностями.
источник
Я, наконец, нашел способ обмануть Stream.reduce, чтобы иметь возможность аккуратно работать с парами значений; есть множество вариантов использования, которые требуют этого средства, которое не появляется естественным образом в JDK 8:
Уловка, которую я использую, - это право возврата; заявление.
источник
reduce
дает достаточно гарантий, чтобы это работало.Элегантным решением будет использование zip . Что-то вроде:
Это довольно лаконично и элегантно, однако в качестве входных данных используется список. Таким образом невозможно обработать бесконечный источник потока.
Другая (гораздо более неприятная) проблема заключается в том, что zip вместе со всем классом Streams недавно был удален из API. Приведенный выше код работает только с версиями b95 или более ранними. Итак, с последним JDK я бы сказал, что нет элегантного решения в стиле FP, и сейчас мы можем просто надеяться, что каким-то образом zip будет повторно введен в API.
источник
zip
был удален. Я не помню все , что было наStreams
классе, но некоторые вещи , которые мигрировали быть статическими методами наStream
интерфейсе, а также естьStreamSupport
иStream.Builder
классы.zip
? Какая бы педантичная причина ни была изобретена, убийство не оправдываетzip
.Это интересная проблема. Подходит ли моя гибридная попытка ниже?
Я считаю, что он не поддается параллельной обработке и, следовательно, может быть дисквалифицирован.
источник
Stream
не файлList
. Конечно, мы также можем извлечь итератор из Stream, так что это может быть правильным решением. Тем не менее, это оригинальный подход.Как отмечали другие, из-за природы проблемы требуется некоторая сохранность состояния.
Я столкнулся с аналогичной проблемой, в которой я хотел, по сути, функцию LEAD Oracle SQL. Моя попытка реализовать это ниже.
источник
Вы можете добиться этого, используя ограниченную очередь для хранения элементов, которые проходят через поток (что основано на идее, которую я подробно описал здесь: возможно ли получить следующий элемент в потоке? )
В примере ниже сначала определяется экземпляр класса BoundedQueue, который будет хранить элементы, проходящие через поток (если вам не нравится идея расширения LinkedList, обратитесь к упомянутой выше ссылке для альтернативного и более общего подхода). Позже вы просто объедините два последующих элемента в экземпляр Pair:
источник
Я согласен с @aepurniet, но вместо карты вы должны использовать mapToObj
источник
Запустите
for
цикл от 0 доlength-1
вашего потокаисточник