У меня есть набор данных, представленный потоком Java 8:
Stream<T> stream = ...;
Я вижу, как отфильтровать его, чтобы получить случайное подмножество - например,
Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();
Stream<T> heads = stream.filter((x) -> (coin.nextInt() == 0));
Я также вижу, как можно уменьшить этот поток, чтобы получить, например, два списка, представляющих две случайные половины набора данных, а затем превратить их обратно в потоки. Но есть ли прямой способ генерировать два потока из исходного? Что-то вроде
(heads, tails) = stream.[some kind of split based on filter]
Спасибо за понимание.
java
java-8
java-stream
user1148758
источник
источник
Stream
в несколькоStream
s без промежуточного преобразования , хотя я думаю, что люди, которые достигли этого вопроса, на самом деле ищут способ достичь этого, независимо от такого ограничения, что является ответом Марка. Это может быть связано с тем, что вопрос в заголовке не такой, как в описании .Ответы:
Не совсем. Вы не можете получить два
Stream
с одного; это не имеет смысла - как бы вы перебрали одно без необходимости генерировать другое одновременно? Поток может быть использован только один раз.Однако, если вы хотите сбросить их в список или что-то, вы можете сделать
источник
stream.collect(...)
for с предопределенным потокобезопаснымCollectors
, который хорошо работает даже в не поточно-безопасных коллекциях (без конфликта синхронизированных блокировок). Лучший ответ @MarkJeronimus.Коллектор может быть использован для этого.
Collectors.partitioningBy()
фабрику.Это позволит создать
Map
отBoolean
доList
, и поставить элементы в один или другой список , основанный наPredicate
.Примечание. Поскольку поток должен потребляться целиком, он не может работать с бесконечными потоками. И поскольку поток все равно используется, этот метод просто помещает их в списки вместо создания нового потока с памятью. Вы всегда можете транслировать эти списки, если вам нужны потоки в качестве вывода.
Кроме того, нет необходимости в итераторе, даже в приведенном вами примере только для заголовков.
Collectors.groupingBy()
фабрику.В случае, если потоки не являются
Stream
, но один из примитивных потоков, какIntStream
, то этот.collect(Collectors)
метод недоступен. Тебе придется делать это вручную, без коллекторской фабрики. Его реализация выглядит так:[Пример 2.0 с 2020-04-16]
В этом примере я инициализирую ArrayLists с полным размером исходной коллекции (если это вообще известно). Это предотвращает события изменения размера даже в худшем случае, но потенциально может поглотить пространство 2 * N * T (N = начальное количество элементов, T = количество потоков). Чтобы найти компромисс между скоростью и быстродействием, вы можете опустить его или использовать наиболее обоснованное предположение, например, ожидаемое наибольшее количество элементов в одном разделе (обычно чуть больше N / 2 для сбалансированного разделения).
Я надеюсь, что никого не оскорбляю, используя метод Java 9. Для версии Java 8 посмотрите историю изменений.
источник
stream.boxed().collect(...);
! Это будет сделано как рекламируется: конвертировать примитивIntStream
в коробочнуюStream<Integer>
версию.(map, x) -> { boolean partition = p.test(x); List<Integer> list = map.get(partition); list.add(x); }
тебя можно просто использовать(map, x) -> map.get(p.test(x)).add(x)
. Кроме того, я не вижу причин, по которымcollect
операция не должна быть поточно-ориентированной. Это работает точно так, как это должно работать, и очень близко к тому, какCollectors.partitioningBy(p)
будет работать. Но я бы использовалIntPredicate
вместо,Predicate<Integer>
если не использоватьboxed()
, чтобы избежать бокса в два раза.Я наткнулся на этот вопрос для себя и чувствую, что у разветвленного потока есть несколько вариантов использования, которые могут оказаться действительными. Я написал приведенный ниже код как потребитель, так что он ничего не делает, но вы можете применить его к функциям и ко всему, с чем вы можете столкнуться.
Теперь ваша реализация кода может выглядеть примерно так:
источник
К сожалению, то, что вы просите, прямо не одобряется в JavaDoc Stream :
Вы можете обойти это, используя
peek
или другие методы, если вы действительно желаете такого поведения. В этом случае, вместо того, чтобы пытаться создать резервные копии двух потоков из одного и того же исходного источника потока с помощью разветвляющегося фильтра, вы дублируете свой поток и фильтруете каждый из дубликатов соответствующим образом.Тем не менее, вы можете пересмотреть,
Stream
является ли структура подходящей для вашего варианта использования.источник
List<Stream> forkStream(Stream s)
но мои результирующие потоки будут по крайней мере частично поддерживаться коллекциями, а не непосредственно базовым потоком, в отличие от того,filter
что не является операцией терминального потока.Это против общего механизма Stream. Скажем, вы можете разделить Stream S0 на Sa и Sb, как вы хотели. Выполнение любой терминальной операции, скажем
count()
, в Sa, обязательно «потребит» все элементы в S0. Поэтому Sb потерял свой источник данных.Раньше у Stream был
tee()
метод, который, я думаю, дублирует поток до двух. Это удалено сейчас.В Stream есть метод peek (), но вы можете использовать его для достижения своих требований.
источник
peek
это именно то, что раньшеtee
.не совсем, но вы можете выполнить то, что вам нужно, вызвав
Collectors.groupingBy()
. вы создаете новую коллекцию, а затем можете создавать экземпляры потоков в этой новой коллекции.источник
Это был наименее плохой ответ, который я мог придумать.
Это берет поток целых чисел и разбивает их на 5. Для тех, кто больше 5, он фильтрует только четные числа и помещает их в список. В остальном он присоединяется к ним с |.
выходы:
Он не идеален, поскольку собирает все в промежуточные коллекции, разрушая поток (и имеет слишком много аргументов!)
источник
Я наткнулся на этот вопрос, ища способ отфильтровать определенные элементы из потока и зарегистрировать их как ошибки. Поэтому мне не нужно было так сильно разбивать поток, как прикреплять преждевременное завершающее действие к предикату с ненавязчивым синтаксисом. Вот что я придумал:
источник
Укороченная версия, которая использует Lombok
источник
Как насчет:
источник