> From: "Viktor Klang" <viktor.kl...@oracle.com> > To: "David Alayachew" <davidalayac...@gmail.com>, "core-libs-dev" > <core-libs-dev@openjdk.org> > Sent: Wednesday, January 10, 2024 2:33:45 PM > Subject: Re: Gatherers -- conditionalWindowFixed?
> Hi David! > Apologies for the late reply, there's been lots of catching up to do after the > holidays. > >I'm really excited for what this will enable for us. > I'm really glad to hear that \uD83D\uDE42 > >It is very much appreciated. > \uD83D\uDC4D >> Could we add one more method for a conditionalWindowFixed? We would need to >> pass >> in some Predicate<T>. If the predicate returns true, create a list (if it >> does >> not already exist) then add the element to it. If the predicate returns false >> while the list is empty, then just move along to the next. Else if the >> predicate returns false while the list is non empty, pass the list down into > > the stream. So, you end up with Stream<T> -----> Stream<List<T>>. > What ends up under Gatherers.* does require careful triaging, ideally by first > seeing user-created implementations being heavily used/useful, then potential > candidate for Gatherers.*, and then at the end it might end up in Stream as a > dedicated method. > By virtue of the Gatherers API, it seems pretty straight-forward for you to > implement what you describe, and personally I'd probably call it something > like > windowBy . > Just typing this up as I write this reply, it could look something like this: > <TR> Gatherer<TR, ?, List<TR>> windowBy(Predicate<TR> includeInCurrentWindow) > { > class State { > ArrayList<TR> window; > boolean integrate(TR element, Gatherer.Downstream<? super List<TR>> > downstream) > { > if (window != null && !includeInCurrentWindow.test(element)) { > var result = Collections.unmodifiableList(window); > window = null; > if (!downstream.push(result)) > return false; > } > if (window == null) > window = new ArrayList<>(); > return window.add(element); > } > void finish(Gatherer.Downstream<? super List<TR>> downstream) { > if (window != null) { > var result = Collections.unmodifiableList(window); > window = null; > downstream.push(result); > } > } > } > return Gatherer.<TR, State, List<TR>>ofSequential(State::new, > State::integrate, > State::finish); > } > jshell> Stream.of("header", "value1", "value2", "header", "header", "value 3", > "value 4", null).gather(windowBy(Predicate.not("header"::equals))).toList() > $1 ==> [[header, value1, value2], [header], [header, value 3, value 4, null]] Hello, I've two questions, 1/ Is there a reason why the integrator is not declared greedy (I'm still not sure to what exactly Greedy means in the context of gatherers) ? 2/ Is there a reason to write the code in a OOP way like you have done instead of only having fields in State and specify the behaviors using lambdas (because with lambdas will you get inference) <T> Gatherer<T, ?, List<T>> windowBy(Predicate<? super T> includeInCurrentWindow) { class State { ArrayList<T> window; } return Gatherer.ofSequential( State::new, (state, element, downstream) -> { ... }, (state, downstream) -> { ... }); } > Cheers, > √ regards, Rémi > Viktor Klang > Software Architect, Java Platform Group > Oracle > From: core-libs-dev <core-libs-dev-r...@openjdk.org> on behalf of David > Alayachew <davidalayac...@gmail.com> > Sent: Wednesday, 10 January 2024 07:05 > To: core-libs-dev@openjdk.org <core-libs-dev@openjdk.org> > Subject: Gatherers -- conditionalWindowFixed? > Hello Core Libs Dev Team, > I have been reading through JEP 461 ( [ https://openjdk.org/jeps/461 | > https://openjdk.org/jeps/461 ] ) about Gatherers, and I'm really excited for > what this will enable for us. > By far, the most important functionality that this API facilitates is the > ability to create windows. Anytime I needed a window, I was basically forced > to > use a for loop. Now, the 2 most common window cases are being handed to us for > free. It is very much appreciated. > Could we add one more method for a conditionalWindowFixed? We would need to > pass > in some Predicate<T>. If the predicate returns true, create a list (if it does > not already exist) then add the element to it. If the predicate returns false > while the list is empty, then just move along to the next. Else if the > predicate returns false while the list is non empty, pass the list down into > the stream. So, you end up with Stream<T> -----> Stream<List<T>>. > The reason I think this is worth adding is because it facilitates a really > common use case. We may not want all windows to be the same size. > Is this something worth adding to the Gatherers API? > Thank you for your time and help! > David Alayachew