<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Hi Archie!</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
>I recently encountered a real-world use case for Stream Gatherers and thought I'd mention it (apologies if you've seen these ideas already). These might even be worth considering including as standard offerings.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
No need to preface your email with an apology ðŸ™‚ I'm happy to get thoughts, feedback, and ideas!</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
You have a pretty interesting use-case, and performing a "sub-group reorder" is an interesting use-case.<br>
Pulling on that string a bit more, it would seem like its primary use-cases would lie in scenarios where you're consuming things like data files (think CSVs etc where there's a predefined order/grouping to the entries) or consuming things like database results,
 would that be a fair characterization?</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Interestingly, one of the exercises I went through during the design of Gatherer was to reimplement the java.util.stream.Stream interface only using Gatherer and Collector, so I took a stab at things like sorted() etc. As is common in the situation of operating
 on top of pre-ordered data, parallelization tends to be costly to implement (either by having to forego it, or by needing to perform much of the operation in the finisher after aggregating elements in the integrator).</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Quickly thinking about the operation, I presume you'd need to be able to track the current "primary group", collect elements into something like an ArrayList, and upon switching to a new primary group, you sort the list according to the secondary group, emit
 all elements for as long as Downstream::push allows you to, clear the list, enqueue the new element which had the new primary group. Then in the finisher you perform the same operation, presuming that that's the signal that there's no more elements in the
 last primary group.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
But I think you can relax the requirement that the primary group must be Comparable, you only need to have a BiPredicate and test (prev, next) for sameness, and if you get false, you presume that `next` belongs to a new primary group. But since you're going
 to sort the group on the secondary, that'll need to be comparable.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="color: inherit;" id="Signature">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Cheers,<br>
√</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b><br>
</b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<b>Viktor Klang</b></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Software Architect, Java Platform Group<br>
Oracle</div>
</div>
<div id="appendonsend" style="color: inherit;"></div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<hr style="display: inline-block; width: 98%;">
<div id="divRplyFwdMsg" dir="ltr" style="color: inherit;"><span style="font-family: Calibri, sans-serif; font-size: 11pt; color: rgb(0, 0, 0);"><b>From:</b> Archie Cobbs <archie.cobbs@gmail.com><br>
<b>Sent:</b> Friday, 20 September 2024 19:20<br>
<b>To:</b> Viktor Klang <viktor.klang@oracle.com><br>
<b>Cc:</b> core-libs-dev@openjdk.org <core-libs-dev@openjdk.org><br>
<b>Subject:</b> [External] : Re: Stream Gatherers (JEP 473) feedback</span>
<div> </div>
</div>
<div style="direction: ltr;">Hi Viktor,</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">I recently encountered a real-world use case for Stream Gatherers and thought I'd mention it (apologies if you've seen these ideas already). These might even be worth considering including as standard offerings.</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">Motivating example: Suppose you have a large list of people sorted by LastName. Your goal is to print the list ordered by LastName, then by FirstName. The list is too large to re-sort the whole thing.</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">Instead, you only need to "fixup" the ordering, by re-sorting just the groups of people with the same last name.</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">If you happen to know that there are no more than 100 people with the exact same last nam, then one option would be a Gatherer that re-sorts a stream, but only up to some maximum window size (if two elements were out of order and
 separated by more than the window size, then sorted output would no longer be guaranteed).</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">In the above example, you would set the window size to 100 and it might look something like this:</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr; margin-left: 40px; font-family: monospace;">listOfPeople.stream()   // sorted by lastName only</div>
<div style="direction: ltr; margin-left: 40px; font-family: monospace;">  .gather(Gatherers.windowSort(100, Comparator.comparing(Person::lastName).thenComparing(Person::firstName)));</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">Another (probably better) option would be a "secondary sort" Gatherer. This would take an already sorted stream and then apply a secondary sort. It would collect items having the same primary sort key (however many there were),
 and then re-sort those groups all at once using the secondary key:</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr; margin-left: 40px; font-family: monospace;">listOfPeople.stream()   // sorted by lastName only</div>
<div style="direction: ltr; margin-left: 40px; font-family: monospace;">  .gather(Gatherers.secondarySort(Comparator.comparing(Person::lastName), Comparator.comparing(Person::firstName)));</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">This kind of thing is common when querying a database that doesn't have the required composite index corresponding to a desired composite sort, e.g., there is an index on LastName and an index on FirstName, but no composite index
 on LastName+FirstName, etc.</div>
<div style="direction: ltr;"><br>
</div>
<div style="direction: ltr;">-Archie</div>
<div style="direction: ltr;"><br>
--</div>
<div style="direction: ltr;">Archie L. Cobbs</div>
</body>
</html>